C++ 11 Regex中的UTF-8字符范围

MCH*_*MCH 30 c++ regex unicode utf-8 c++11

这个问题是Do C++ 11正则表达式与UTF-8字符串一起使用的扩展吗?

#include <regex>  
if (std::regex_match ("?", std::regex("?") ))  // "\u4e2d" also works
  std::cout << "matched\n";
Run Code Online (Sandbox Code Playgroud)

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

clang++ -std=c++0x -stdlib=libc++
Run Code Online (Sandbox Code Playgroud)

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

if (std::regex_match ("?", std::regex("[?-?????]")))
  std::cout << "range matched\n";
Run Code Online (Sandbox Code Playgroud)

改变语言环境也没有帮助.有任何想法吗?

编辑

所以我发现如果你添加+到最后,所有范围都有效.在这种情况下[?-?????]+,但如果你添加{1} [?-?????]{1}它不起作用.而且,它似乎超越了它的界限.它不会匹配拉丁字符,但它会匹配?这是\u306f?\u3041.他们都躺在下面\u4E00

nhahtdh还提出了regex_search,它也可以在不增加的情况下工作,+但它仍然会遇到与上面相同的问题,因为它会超出其范围.同时也使用了语言环境.Mark Ransom建议它将UTF-8字符串视为一组愚蠢的字节,我认为这可能就是它所做的.

进一步推动UTF-8变得混乱的理论[a-z]{1}[a-z]+匹配a,但只[?-?????]+匹配任何角色,而不是[?-?????]{1}.

R. *_*des 34

以UTF-8编码,字符串"[?-?????]"等于这一个:"[\xe4\xb8\x80-\xe9\xbe\xa0\xe3\x80\x85\xe3\x80\x86\xe3\x83\xb5\xe3\x83\xb6]".这不是您正在寻找的机器人角色类.

您正在寻找的角色类包括:

  • U + 4E00..U + 9FA0范围内的任何字符; 要么
  • 任何字符々,〆,ヵ,ヶ.

您指定的字符类包括:

  • 任何"字符"\ xe4或\ xb8; 要么
  • \ x80 ..\xe9范围内的任何"字符"; 要么
  • 任何"字符"\ xbe,\ xa0,\ xe3,\ x80,\ x85,\ xe3(再次),\ x80(再次),\ x86,\ xe3(再次),\ x83,\ xb5,\ xe3 (再次),\ x83(再次),\ xb6.

凌乱不是吗?你看到了问题吗?

这与"拉丁"字符不匹配(我假设你的意思是像az这样的东西),因为在UTF-8中,所有字符都使用低于0x80的单个字节,而这些字符都不在那个混乱的字符类中.

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

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

如果你改为添加{1}它不匹配,因为我们回到匹配三个"字符"对一个.

顺便说一下"?"比赛"?",因为我们以同样的顺序匹配三个"人物"对相同的三个"角色".

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

更大的问题是你正在使用一个甚至没有1级支持Unicode的正则表达式库,这是最低要求.它会消耗大量的字节,而且你的珍贵的小正则表达式对它没有多大帮助.

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

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

哦,对,这不适用于C++ 11正则表达式.在那里,我几乎忘记了那些比使用Unicode无用的烦人.

那你该怎么办?

您可以将输入解码为a std::u32stringchar32_t全部用于匹配.这不会给你这个烂摊子,但当你的意思是"一组共享某个属性的字符"时,你仍然会硬编码范围和异常.

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

  • @MCH是的,我想抓住ICU进行一场小小的比赛可能会太多了.如果你想使用Unicode和正则表达式,Perl几乎是唯一认真对待它的语言.这是一种令人悲伤的事态,但这就是我们所拥有的.我个人认为`<regex>`是stdlib中的一些垃圾.它是2013年,假装Unicode不存在是滑稽的,只有这个想法,处理Unicode太痛苦无法照顾(提示:如果你的锤子没有头,你将很难驾驶指甲). (9认同)