为什么没有提供std :: regex_traits <char32_t>(因此没有std :: basic_regex <char32_t>)的定义?

时间:2015-11-14 13:27:07

标签: c++ regex c++11

我想在UTF-32代码点上使用正则表达式,并发现这个reference声明std :: regex_traits必须由用户定义,以便可以使用std :: basic_regex。未来似乎没有计划改变。

  1. 为什么会这样呢?

  2. 这是否与Unicode说组合代码点必须被视为等于单代码点表示(如同单个代码点表示的变音符号'或带有a和点的事实有关)作为两个独立的)?

  3. 鉴于只支持单码位字符的简化,这种特性是否可以轻易定义,或者这可能是非平凡的还是需要进一步的限制?

1 个答案:

答案 0 :(得分:7)

  1. 正则表达式匹配的某些方面是区域设置感知的,结果是std::regex_traits对象包含或引用std::locale对象的实例。 C ++标准库仅提供charwchar_t个字符的区域设置,因此char32_t没有标准区域设置(除非它恰好与wchar_t相同),并且这种限制延续到了正则表达式。

  2. 您的描述不准确。 Unicode定义了两个字符串之间的规范等价关系,它基于使用NFC或NFD对两个字符串进行规范化,然后逐个代码点地比较规范化值。它没有将规范等价简单地定义为代码点和代码点序列之间的等价,因为规范化不能简单地逐个字符地完成。规范化可能需要将组成字符重新排序为规范顺序(在规范(de)组合之后)。因此,它不容易适合区域设置转换的C ++模型,通常是单字符。

    C ++标准库没有实现任何Unicode规范化算法;在C ++中,与许多其他语言一样,两个字符串L"\u00e4"(ä)和L"\u0061\u0308"(ä)将作为不同的比较,尽管它们在规范上是等价的,并且像人类读者一样看待相同的字形。 (在我正在写这个答案的机器上,这两个字素的渲染略有不同;如果仔细观察,你会发现第二个字母中的变音符号稍微偏离其视觉上最佳位置。这违反了Unicode要求规范等效字符串具有完全相同的渲染。)

    如果要检查两个字符串的规范等效性,则需要使用Unicode规范化库。不幸的是,C ++标准库不包含任何此类API;您可以查看ICU(其中还包括Unicode-aware regex matching)。

    在任何情况下,正则表达式匹配 - 在C ++标准中指定的范围 - 不规范化目标字符串。这是Unicode Technical Report on regular expressions允许的,它建议将目标字符串显式规范化为某种规范化形式,并编写模式以使用规范化为该形式的字符串:

      

    对于大多数功能齐全的正则表达式引擎,在规范等效性下进行匹配非常困难,这可能涉及字符的重新排序,拆分或合并....实际上,正则表达式API未设置为匹配部分字符或处理不连续的选择。还有许多其他边缘情况......然而,构建与NFD(或NFKD)文本匹配的模式是可行的。这可以通过以下方式完成:

         
        
    • 将要匹配的文本放入已定义的规范化表单(NFD或NFKD)。
    •   
    • 让用户设计正则表达式模式以匹配定义的规范化表单。例如,模式不应包含在该规范化形式中不会出现的字符,也不应包含不会发生的序列。
    •   
    • 像往常一样,按代码点在代码点上应用匹配算法。
    •   
  3. 创建char32_t std::regex_traits专业化的大部分工作都是创建char32_t语言环境对象。我从来没有尝试过做这些事情;我怀疑它需要相当多的注意细节,因为有很多奇怪的角落情况。

  4. C ++标准对于正则表达式匹配的细节有些模糊,将详细信息留给了有关正则表达式的每种风格的外部文档(并且没有关于如何将这些外部规范应用于除了每个之外的字符类型的完整说明味道是指定的)。但是,可以推断出匹配是逐个字符的事实。例如,在第28.3节“需求[re.req]”中,表136包含负责逐个字符等价算法的语言环境方法:

      

    表达式:v.translate(c)      返回类型:X::char_type      断言:返回一个字符,对于任何被认为等同于d然后c的字符v.translate(c) == v.translate(d)

    类似地,在默认“Modified ECMAScript”风格(第28.13节)的正则表达式匹配描述中,标准描述了正则表达式引擎如何匹配两个字符(模式中的一个和目标中的一个):(第14.1)段:

      

    在将正则表达式有限状态机与字符序列进行匹配期间,使用以下规则比较两个字符cd

         
        
    1. (flags() & regex_constants::icase)如果traits_inst.translate_nocase(c) == traits_inst.translate_nocase(d),则flags() & regex_constants::collate两个字符相等;

    2.   
    3. 否则,traits_inst.translate(c) == traits_inst.translate(d)如果c == d,则{{1}}两个字符相等;

    4.   
    5. 否则,如果{{1}},则两个字符相等。

    6.