C语言 预组合/分解匹配的正则表达式

yhxst69z  于 2023-04-05  发布在  其他
关注(0)|答案(1)|浏览(101)

人类会认为以下字符串表示相同的文本:

>>> [b'a\xc3\xa9b'.decode('utf-8'), b'ae\xcc\x81b'.decode('utf-8')]
['aéb', 'aéb']

一个字符串使用预组合字符,另一个使用分解字符,但生成的文本是相同的。
但是,ICU似乎不支持匹配预合成和分解的字符:

UParseError pe;
UErrorCode status;
URegularExpression *regexp = uregex_open(L"a\u0065\u0301b", 4, URegexpFlag::UREGEX_CASE_INSENSITIVE, &pe, &status);
uregex_setText(regexp, L"a\u00E9b", 3, &status);
UBool success = uregex_matches(regexp, 0, &status);  // fails
uregex_close(regexp);

PCRE也没有:

$ LC_ALL=en_US.UTF-8 pcretest <(printf '%s\n' $'/ae\xcc\x81b/i' $'a\xc3\xa9b')
PCRE version 8.45 2021-06-15

/aéb/
aéb
No match

所以,如果我想处理任意正则表达式的这种情况(以便结果对人类有意义)......那么我该怎么做呢?
有没有一种方法可以让现有的库在任意Unicode正则表达式和语料库中正确工作?
是否存在任何正则表达式库可以完全处理Unicode(除了全大小写折叠等)?
理想情况下,我希望我可以在C++中使用的东西,但其他语言的解决方案也很受欢迎。

5kgi1eie

5kgi1eie1#

如果你想比较两个字符串的等价性,而不管它们的标准化形式如何,ICU有unorm_compare()。例如:

// g++ -Wall -Wextra -O $(icu-config --cppflags --cxxflags --ldflags --ldflags-icuio) -o demo demo.cpp
#include <cstdlib>
#include <iostream>
#include <unicode/unorm2.h>
#include <unicode/unistr.h>
#include <unicode/ustream.h>

int main(void) {
  UErrorCode err = U_ZERO_ERROR;
  icu::UnicodeString a{u"a\u0065\u0301b"}, b{u"a\u00E9b"};

  int res = unorm_compare(a.getBuffer(), a.length(),
                          b.getBuffer(), b.length(),
                          U_COMPARE_IGNORE_CASE, &err);
  if (U_FAILURE(err)) {
    std::cerr << "unorm_compare() error: " << u_errorName(err) << '\n';
    return EXIT_FAILURE;
  }

  if (res == 0) {
    std::cout << a << " and " << b << " are equivalent.\n";
  } else {
    std::cout << a << " and " << b << " differ.\n";
  }
}

在编译和运行时,打印出

aéb and aéb are equivalent.

相关问题