【问题标题】:How to make std::regex match Utf8如何使 std::regex 匹配 Utf8
【发布时间】:2018-12-01 02:58:18
【问题描述】:

我想要一个像“.c”这样的模式,匹配“.”任何 utf8 后跟 'c' 使用 std::regex。

我在 Microsoft C++ 和 g++ 下尝试过。我得到相同的结果,每次“。”只匹配一个字节。

这是我的测试用例:

#include <stdio.h>
#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main(int argc, char** argv)
{
    // make a string with 3 UTF8 characters
    const unsigned char p[] = { 'a', 0xC2, 0x80, 'c', 0 };
    string tobesearched((char*)p);

    // want to match the UTF8 character before c
    string pattern(".c");
    regex re(pattern);

    std::smatch match;
    bool r = std::regex_search(tobesearched, match, re);
    if (r)
    {
        // m.size() will be bytes, and we expect 3
        // expect 0xC2, 0x80, 'c'

        string m = match[0];
        cout << "match length " << m.size() << endl;

        // but we only get 2, we get the 0x80 and the 'c'.
        // so it's matching on single bytes and not utf8
        // code here is just to dump out the byte values.
        for (int i = 0; i < m.size(); ++i)
        {
            int c = m[i] & 0xff;
            printf("%02X ", c);
        }
        printf("\n");
    }
    else
        cout << "not matched\n";

    return 0;
}

我希望模式“.c”与我的 tobesearched 字符串的 3 个字节匹配,其中前两个是 2 个字节的 utf8 字符,后跟“c”。

【问题讨论】:

  • 使用宽字符和 UTF32(如果你的编译器只支持 UTF16),或者使用支持 UTF-8 的第三方正则表达式库。标准 C++ 中没有解决方案。
  • 所以基本上std::regex不支持utf8?我确实有另一个确实的正则表达式库,但我期待标准库支持这一点。
  • 标准中的 Unicode 支持几乎不存在。

标签: c++ regex utf-8


【解决方案1】:

一些正则表达式支持\X,它将匹配单个 unicode 字符,该字符可能由多个字节组成,具体取决于编码。正则表达式引擎在引擎设计使用的编码中获取主题字符串的字节是一种常见的做法,因此您不必担心实际编码(无论是 US-ASCII、UTF-8、 UTF-16 或 UTF-32)。

另一个选项是\uFFFF,其中 FFFF 指的是 unicode 字符集中该索引处的 unicode 字符。这样,您可以在字符类中创建范围匹配,即[\u0000-\uFFFF]。同样,这取决于正则表达式支持的内容。 \x{...} 中的 \u 有另一个变体,它做同样的事情,除了必须在花括号内提供 unicode 字符索引,并且不需要填充,例如\x{65}.

编辑:这个网站非常棒,可以了解更多关于各种风格的正则表达式https://www.regular-expressions.info

编辑 2:要匹配任何 Unicode 专有字符,即不包括 ASCII 表中的字符/1 字节字符,您可以尝试"[\x{80}-\x{FFFFFFFF}]" 即任何值为 128-4,294,967,295 的字符这是从 ASCII 范围之外的第一个字符到当前使用最多 4 字节表示的最后一个 unicode 字符集索引(最初是 6,将来可能会更改)。

不过,通过单个字节循环会更有效:

  1. 如果前导位为 0,即如果其有符号值为 &gt; -1,则它是 1 字节字符表示。跳到下一个字节并重新开始。
  2. 否则,如果前导位为 11110,即其有符号值为 &gt; -17n=4
  3. 否则,如果前导位为 1110,即其有符号值为 &gt; -33n=3
  4. 否则,如果前导位为 110,即其有符号值为 &gt; -65n=2
  5. (可选)检查下一个 n 字节是否都以 10 开头,即对于每个字节,如果它具有符号值 &lt; -63,则它是无效的 UTF-8 编码。
  6. 您现在知道前面的 n 个字节构成一个 unicode 独占字符。因此,如果 NEXT 字符是“c”,即== 99,您可以说它匹配 - return true

【讨论】:

  • 也许我误解了你在找什么?当您说 UTF-8 字符时,您的意思是“任何有效的 UTF-8 字符”,即包括 ASCII 表 (0-127) 还是指 ASCII 表之外的字符?如果字符长度只有 1 个字节,您不想匹配吗?如果是这样,您需要一种基于非正则表达式的方法。 UTF-8 很容易解释。如果第一位为 0,则长度为 1 个字节。如果不是,它是多字节字符中的单字节,并且您知道前面的字符> 127。如果要确保编码正确,只需从前导字节开始计数。
  • 感谢您的更新。我想要点“。”匹配任何字符,包括单字节和多字节。然后我会将生成的字符串匹配解释为 utf8。看起来std::regex 不像这样工作。真可惜。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多