1

下午好,我们在 WINDOWS Visual Studio 8.0 和 9.0 上使用带有 PCRE_CASELESS、PCRE_UTF8、PCRE_UCP 的最新 C/C++ 版本的 PCRE。当我们使用 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。这可能吗?谢谢你。

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

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());
}
}
4

3 回答 3

2

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

解释:

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

.匹配任何字符。

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

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

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

于 2012-06-25T20:51:15.637 回答
1

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

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


发件人:Philip Hazel 日期:2012 年 6 月 26 日星期二上午 8:55 收件人:Frank Chang 抄送:pcre-dev@exim.org

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

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

regex: '(?=. \x{00F6})(?=. \x{00E4})' 它尝试使用使用 ?= 或正向前瞻来确保两个 UTF-8 代码点以任一顺序匹配。

PCRE_compile() 返回 OK 并且 PCRE_execute() 在字符串 DAS tausendschöne Jungfräulein 上返回 OK。在十六进制中,它是 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,而不是使用 PCRE '\x{00F6}.*\x{00E4}' 正则表达式时获得的 GetMatchStart() = 14 和 GetMatchEnd() = 27。请告知我们是否可以在 PCRE 正则表达式中对多个 UTF-8 代码点进行顺序不敏感匹配。谢谢你。

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

由于您的正则表达式完全由断言组成,因此实际匹配的字符串为空(如 pcretest 所示)。如果您想为您提供匹配的开始和结束,您需要修改您的正则表达式以实际匹配某些内容。如果您想要的是这两个代码点之间的字符串,无论是哪种顺序,都可以像这样简单

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

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

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

菲利普

——菲利普·黑泽尔

于 2012-06-26T17:16:00.007 回答
0

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

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

这似乎运行正常。

于 2012-06-26T13:53:17.873 回答