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



这个问题是c++ 11正则表达式与UTF-8字符串工作吗?

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

该程序是在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 matchedn";

改变区域设置也没有帮助。什么好主意吗?

<标题>编辑

所以我发现如果在末尾添加+,所有范围都可以工作。在本例中,[一-龠々〆ヵヶ]+,但如果您添加{1} [一-龠々〆ヵヶ]{1},它不起作用。此外,它似乎超出了自己的界限。它不会匹配拉丁字符,但会匹配(即u306f)和(即u3041)。它们都位于u4E00

之下

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

进一步推动了UTF-8在某种程度上被混淆的理论,[a-z]{1}[a-z]+匹配a,但只有[一-龠々〆ヵヶ]+匹配任何字符,而不是[一-龠々〆ヵヶ]{1}

用UTF-8编码,字符串"[一-龠々〆ヵヶ]"等于这个字符串:"[xe4xb8x80-xe9xbexa0xe3x80x85xe3x80x86xe3x83xb5xe3x83xb6]"。这不是你要找的机器人角色类。

您正在寻找的字符类是包含:

的字符类。
  • U+4E00 ~ U+9FA0范围内的任意字符;或
  • 任意字符(,,,.
  • )

指定的字符类包含:

  • 任何"characters" xe4或xb8;或
  • 任何"字符"在x80..xe9;或
  • 任意"字符" xbe, xa0, xe3, x80, x85, xe3(再一次),x80(再一次),x86, xe3(再一次),x83, xb5, xe3(再一次),x83(再一次),x83(再一次),x83(再一次),xb6。

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

这将不匹配"拉丁"字符(我假设你指的是像a-z这样的东西),因为在UTF-8中,这些字符都使用0x80以下的单个字节,并且这些字符都不在那个混乱的字符类中。

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

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

如果你添加{1},它将不匹配,因为我们又回到了三个"字符"对一个字符的匹配。

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

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

更大的问题是,您使用的regex库甚至不支持Unicode的1级支持,这是最低要求。它会改变字节,你宝贵的小正则表达式对此无能为力。

更大的问题是,你正在使用一组硬编码的字符来指定"任何日本汉字或汉字"。为什么不使用Unicode Script属性呢?

R"(p{Script=Han})"

哦,对了,这在c++ 11的正则表达式中不起作用。有那么一刻,我几乎忘记了它们在Unicode中比无用更糟糕。

那么你应该怎么做呢?

您可以将输入解码为std::u32string,并使用char32_t进行匹配。这不会给你带来这种混乱,但是当你指的是"一组共享某种属性的字符"时,你仍然会硬编码范围和异常。

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

最新更新