C/C++ PCRE 是否可以匹配 2 个或多个 UTF-8 代码点,这些代码点在 UTF-8 字符串中彼此相距甚远

Is it possible for C/C++ PCRE to match 2 or more UTF-8 codepoints which are far apart from each other in a UTF-8 String?

本文关键字:UTF-8 代码 相距甚远 字符串 是否 PCRE C++      更新时间:2023-10-16

下午好,我们在WINDOWS Visual Studio 8.0和9.0上使用最新的C/C++版本的PCRE,具有PCRE_CASELESS,PCRE_UTF8,PCRE_UCP。当我们使用 PCRE 正则表达式 [\x{00E4}] 时{1}我们能够将标准拉丁语码位 U+00E4 与字符串 DAS tausendschã¶ne Jungfräulein(也称为 44 41 53 20 74 61 75 73 65 6E 64 73 63 68 C3 B6 6E 65 20 4A 75 6E 67 66 72 C3 A4 75 6C 65 69 6E。 现在我们想匹配代码点 U+00E4(即 C3 B6)和 U+00F6(即 C3 A4),这样我们就可以实现一个简单的原型 C/C++ 搜索和替换操作 $1 $2。这可能做到吗?谢谢。

我们现在使用具有以下C++函数的 PCRE 正则表达式[x{00F6}x{00E4}]{1,}

void cInternational::RegExSearchReplace(cOrderedList *RegExList_,char **Input_) {
    const char *replacement;
    char substitution[dMaxRegExSubstitution];
    int subString;
    cPCRE *regEx;
    unsigned char* Buffer;
    Buffer = new unsigned char[1024];
    if (*Input_[0]!='x0' && RegExList_->ResetIterator()) {
        do {
            regEx=new cPCRE();
            regEx->SetOptions(PCRE_CASELESS);
            if (regEx->Compile(RegExList_->GetCharacterField(1))) {
                // Search for Search RegEx:
                while (regEx->Execute((char *)Buffer)>0) {
                   // Found it, get Replacement expression:
                   replacement=RegExList_->GetCharacterField(2);
                    int subLen=0;
// Build substitution string by finding each $# in replacement and replacing
//   them with the appropriate found substring. Other characters in replacment
//   are sent through, untouched.
    for (int i=0;replacement[i]!='x0';i++) {
if (replacement[i]=='$' && isdigit(replacement[i+1])) {
      subString=atoi(replacement+i+1);
      if (regEx->HasSubString(subString)) {
strncpy(substitution+subLen,
       *Input_+regEx->GetMatchStart(),
        regEx->GetMatchEnd() - regEx->GetMatchStart());
        subLen+=(regEx->GetMatchEnd() - regEx->GetMatchStart()
     }
     i++
  } else {
     substitution[subLen++]=replacement[i];
  }
}
substitution[subLen]='x0';
// Adjust the size of Input_ accordingly:
int sizeDiff=strlen(substitution)-(regEx->GetMatchEnd()-regEx->GetMatchStart());
if (sizeDiff>0) {
    char *newInput=new char[strlen(*Input_)+sizeDiff+1];
    strcpy(newInput,*Input_);
    delete[] *Input_;
    *Input_=newInput;
}
memmove(*Input_ + regEx->GetMatchStart() + 1,
        *Input_+regEx->GetMatchEnd() + 1,
        regEx->GetMatchEnd()- regEx->GetMatchStart());
strncpy(*Input_,substitution,strlen(substitution));
(*Input_)[strlen(substitution)] = 'x0';
Buffer = Buffer + regEx->GetMatchEnd();
}
}
delete regEx;
} while (RegExList_->Next());
}
}

使用 PCRE,您用来匹配字符串中任何位置出现的正则表达式如下: x{00E4}.*x{00F6}

解释:

x{00E4}匹配您要查找的第一个 Unicode 字符。

.匹配任何字符。

*修改前一个期间以匹配 0 次或更多次。这将允许第二个 unicode 字符是任意数量的字符。

x{00F6}匹配您要查找的第二个 Unicode 字符。

如果它们出现,这将匹配。让我知道它是如何工作的,如果您需要它来做其他事情,等等(例如:这对于搜索和替换操作似乎不是那么有用。它只是会告诉你这些字符是否存在于字符串中。您需要修改正则表达式才能进行替换。

昨晚我给PCRE的开发人员Phip Hazel发了一封电子邮件。 Hazel 先生认为,可以实现对顺序不敏感的 PCRE 正则表达式,例如\x{00f6}.?\x{00e4} | \x{00e4}。?\x{00f6}

说明如下所示。谢谢你的帮助,达蒙。问候,弗兰克


寄件人:菲利普·黑兹尔日期: 2012年6月26日 星期二 at 8:55 上午致:张旭东抄送:pcre-dev@exim.org

2012年6月25日星期一,Frank Chang写道:

晚上好,我们正在使用 C/C++ PCRE 8.30 和 PCRE_UTF8 |PCRE_UCP | PCRE_COLLATE。这是一个不区分顺序的

正则表达式:"(?=.\x{00F6})(?=.\x{00E4})' 它尝试使用 ?= 或正数 向前看,确保两个 UTF-8 码位按任一顺序匹配。

PCRE_compile() 返回 OK,PCRE_execute() 返回字符串 DAS 上的 OK tausendschã¶ne Jungfrã¤ulein .十六进制为 44 41 53 20 74 61 75 73 65 6E 64 73 63 68 C3 B6 6E 65 20 4A 75 6E 67 66 72 C3 A4 75 6C 65 69 6E. 但是,GetMatchStart() 返回 0,GetMatchEnd() 返回 0 而不是 GetMatchStart() = 14 和 GetMatchEnd() = 27,我们在以下情况下获得 我们使用 PCRE '\x{00F6}.*\x{00E4}' 正则表达式。 请告知我们是否可以进行订单不敏感匹配 PCRE 正则表达式中的多个 UTF-8 代码点。谢谢。

我已经通过基本的pcretest程序运行了您的正则表达式,并且它匹配。这证实了您使用 PCRE_compile() 的发现和PCRE_execute()。

由于您的正则表达式完全由断言组成,因此实际匹配的字符串为空(如 PCRETEST 所示)。您需要将正则表达式修改为实际上匹配一些东西,如果你想给出一个匹配的开始和结束给你。如果你想要的是这两个代码点之间的字符串,在要么顺序,简单的东西,比如

\x{00f6}.?\x{00e4} | \x{00e4}。?\x{00f6}

(忽略空格)应该做你想做的事。

我意识到这个例子可能是你真实的简化应用程序,我的简单建议不能很好地扩展。但是要点:如果你想提取字符串,你的正则表达式必须做一些实际的匹配,而不仅仅是断言。

菲利普

--菲利普·黑兹尔

我们编写了一个 PCRE 顺序不敏感的正则表达式。

(?=.+(x{00F6})){1}(?=.+(x{00E4})){1}

这似乎功能正常。