C++11正则表达式是否适用于UTF-8字符串?

28

如果我想使用C++11的正则表达式处理Unicode字符串,能否直接使用UTF-8编码的char*,还是必须将其转换为wchar_t*类型的字符串?


7
这里是否存在关于Unicode/码点和Unicode编码方案的混淆?请问需要翻译此段内容吗? - Maarten Bodewes
1
http://icu-project.org/apiref/icu4c/classUnicodeString.html - Ωmega
4个回答

18

您需要测试编译器和所使用的系统,但理论上,如果您的系统有UTF-8语言环境,则应该会支持。在Clang/OS X上,以下测试对我返回了true。

bool test_unicode()
{
    std::locale old;
    std::locale::global(std::locale("en_US.UTF-8"));

    std::regex pattern("[[:alpha:]]+", std::regex_constants::extended);
    bool result = std::regex_match(std::string("abcdéfg"), pattern);

    std::locale::global(old);

    return result;
}

注意:这是在一个UTF-8编码的文件中编译的。


为了安全起见,我还使用了明确十六进制版本的字符串。也可以工作。

bool test_unicode2()
{
    std::locale old;
    std::locale::global(std::locale("en_US.UTF-8"));

    std::regex pattern("[[:alpha:]]+", std::regex_constants::extended);
    bool result = std::regex_match(std::string("abcd\xC3\xA9""fg"), pattern);

    std::locale::global(old);

    return result;
}

更新:对我而言test_unicode()仍然可用。

$ file regex-test.cpp 
regex-test.cpp: UTF-8 Unicode c program text

$ g++ --version
Configured with: --prefix=/Applications/Xcode-8.2.1.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode-8.2.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

6
如果您使用u8"abcdéfg",则无需将源代码保存为UTF-8格式。 - R. Martinho Fernandes
地域设置很重要吗?你是否可以完全忽略它? - Viet
1
@Viet,总是有一个区域设置。如果您没有明确设置所需的区域设置,则正则表达式将使用现有的区域设置进行处理。如果区域设置与UTF-8不兼容,则不会预期正则表达式能够处理UTF-8字符串。 - Jeffery Thomas
@JefferyThomas:是的,我确定源代码是utf-8编码(虽然使用u8""并不是必须的)。test_unicode()test_unicode2()都返回falseg++ -std=c++11 *.cc && ./a.out)。无论ideone使用什么,都会产生相同的结果 - jfs
1
@EgbertS 我所呈现的代码是针对UTF-8(一种多字节编码)的。如果日语文本已经被编码为UTF-8字符串,则该代码将可正常工作。如果您使用其他编码(如Shift-JIS),则需要将其转换为UTF-8。 - Jeffery Thomas
显示剩余6条评论

2

C++11的正则表达式对UTF-8的支持还算可以,但只是最基本的支持。如果你想要完整的Unicode正则表达式支持来处理UTF-8字符串,最好使用直接支持该功能的库,例如http://www.pcre.org/


2
@ildjarn:......需要编译支持ICU,但不幸的是,并非所有平台都遵循此规则,而且可能很难使其正常工作。然而,ICU具有自己的正则表达式支持... - DevSolar

0

是的,这是UTF-8编码的设计原则。如果将字符串视为字节数组而不是代码点数组,则子字符串操作应该可以正常工作。

请参见此处的FAQ#18:http://www.utf8everywhere.org/#faq.validation,了解如何在此编码设计中实现此目标。


2
正则表达式匹配不是“子字符串操作”。 - R. Martinho Fernandes

-1

我有一个使用案例,需要在查找笛卡尔坐标时处理可能的Unicode字符串,这个示例展示了我如何按照建议使用std::wregexstd::wstring来处理解析模块中的可能的Unicode字符。

static bool isCoordinate(std::wstring token)
{   
    std::wregex re(L"^(-?[[:digit:]]+)$");
    std::wsmatch match;
    return std::regex_search(token, match, re);
}

int wmain(int argc, wchar_t * argv[])
{
    // Testing against not a number nor unicode designation
    bool coord = ::isCoordinate(L"أَبْجَدِيَّة عَرَبِيَّة‎中文"); 

    if (!coord)
        return 0;
    return 1;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接