c++ - C++11 正则表达式中的 UTF-8 字符范围

标签 c++ regex unicode utf-8 c++11

这个问题是 Do C++11 regular expressions work with UTF-8 strings? 的延伸

#include <regex>  
if (std::regex_match ("中", std::regex("中") ))  // "\u4e2d" also works
  std::cout << "matched\n";

该程序是在 Mac Mountain Lion 上使用 clang++ 编译的,具有以下选项:

clang++ -std=c++0x -stdlib=libc++

上面的代码有效。这是一个标准范围正则表达式 "[一-龠々〆ヵヶ]" 用于匹配任何日文汉字或中文字符。它适用于 Javascript 和 Ruby,但我似乎无法在 C++11 中使用范围,即使使用类似的版本 [\u4E00-\u9fa0]。下面的代码与字符串不匹配。

if (std::regex_match ("中", std::regex("[一-龠々〆ヵヶ]")))
  std::cout << "range matched\n";

更改语言环境也无济于事。有什么想法吗?

编辑

所以我发现,如果您在末尾添加 +,所有范围都有效。在这种情况下[一-龠々〆ヵヶ]+,但是如果你添加{1} [一-龠々〆ヵヶ]{1}它不起作用。此外,它似乎超出了它的界限。它不会匹配拉丁字符,但会匹配 \u306f\u3041。它们都位于 \u4E00

之下

nhahtdh 还建议 regex_search 也可以在不添加 + 的情况下工作,但通过将值拉到其范围之外,它仍然会遇到与上述相同的问题。也玩了一些语言环境。 Mark Ransom 建议它将 UTF-8 字符串视为一组愚蠢的字节,我认为这可能就是它正在做的事情。

进一步插入 UTF-8 变得困惑的理论,[a-z]{1}[a-z]+ 匹配 a,但只有 [一-龠々〆ヵヶ]+ 匹配任何字符,而不是 [一-龠々〆ヵヶ]{1}

最佳答案

UTF-8编码,字符串"[一-龠々〆ヵヶ]"等于这个:"[\xe4\xb8\x80-\xe9\xbe\xa0\xe3\x80\x85\xe3\x80\x86\xe3\x83\xb5\xe3\x83\xb6]"。这不是您要查找的 droid 字符类。

您要查找的字符类包括:

  • U+4E00..U+9FA0 范围内的任意字符;或
  • 任何字符々、〆、ヵ、ヶ。

您指定的字符类包括:

  • 任何“字符”\xe4 或\xb8;或
  • \x80..\xe9 范围内的任何“字符”;或
  • 任何“字符”\xbe、\xa0、\xe3、\x80、\x85、\xe3(再次)、\x80(再次)、\x86、\xe3(再次)、\x83、\xb5 、\xe3(再次)、\x83(再次)、\xb6。

是不是很乱?看到问题了吗?

这将不匹配“拉丁”字符(我假设您的意思是 a-z 之类的),因为在 UTF-8 中,它们都使用低于 0x80 的单个字节,并且这些字符都不属于那个杂乱的字符类。

它也不会匹配 "中" 因为 "中" 有三个“字符”,而您的正则表达式只匹配那个奇怪的长列表中的一个“字符” .试试 assert(std::regex_match("中", std::regex("..."))) 你会看到。

如果你添加一个 + 它会起作用,因为 "中" 在你奇怪的长列表中有三个“字符”,现在你的正则表达式匹配一个或多个。

如果您改为添加 {1},则它不匹配,因为我们又将三个“字符”与一个匹配。

顺便说一下 "中" 匹配 "中" 因为我们将三个“字符”与相同的三个“字符”以相同的顺序匹配。

带有 + 的正则表达式实际上会匹配一些不需要的东西,因为它不关心顺序。可以从 UTF-8 中的字节列表生成的任何字符都将匹配。它将匹配 "\xe3\x81\x81" (ぁ U+3041),它甚至会匹配无效的 UTF-8 输入,例如 "\xe3\xe3\xe3\xe3".

更大的问题是您使用的正则表达式库甚至没有对 Unicode 的 1 级支持,这是最低要求。它会处理字节数,而您宝贵的小型正则表达式对此无能为力。

更大的问题是您使用一组硬编码的字符来指定“任何日文汉字或汉字”。为什么不使用 Unicode Script 属性呢?

R"(\p{Script=Han})"

哦,对了,这不适用于 C++11 正则表达式。有那么一瞬间,我几乎忘记了那些 Unicode 比没用更烦人。

那你该怎么办?

您可以将输入解码为 std::u32string 并使用 char32_t 进行匹配。这不会给您带来麻烦,但是当您的意思是“一组共享某个属性的字符”时,您仍然会硬编码范围和异常。

我建议你忘记 C++11 正则表达式并使用一些具有最低 1 级 Unicode 支持的正则表达式库,如 ICU 中的那个。 .

关于c++ - C++11 正则表达式中的 UTF-8 字符范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15882991/

相关文章:

python - 如何在 Python 3 中设置 sys.stdout 编码?

c++ - 如何在单个 cout 中对多个变量进行 set.precision

c++ - 使用参数 C++ 调用 std::thread 函数时出现编译器错误

c++ - 在 Xcode、mac 中找不到 gmp.h 文件错误

javascript - 正则表达式 - 记录右组(Javascript)

regex - Hive 查询仅替换第一次出现的子字符串

ruby 1.9 : Convert byte array to string with multibyte UTF-8 characters

c++ - C++ 中的列表函数

python - Python中的负模式匹配正则表达式

Android 2.3 Unicode 支持