<regex> 遇到西里尔字符问题
<regex> having trouble with Cyrillic characters
我正在尝试使用标准 <regex>
库来匹配一些西里尔文字:
// This is a UTF-8 file.
std::locale::global(std::locale("en_US.UTF-8"));
string s {"Каждый охотник желает знать где сидит фазан."};
regex re {"[А-Яа-яЁё]+"};
for (sregex_iterator it {s.begin(), s.end(), re}, end {}; it != end; it++) {
cout << it->str() << "#";
}
但是,这似乎不起作用。上面的代码产生以下结果:
Кажд�#й#о�#о�#ник#желае�#зна�#�#где#�#иди�#�#азан#
而不是预期的:
Каждый#охотник#желает#знать#где#сидит#фазан
上面'��'符号的代码是1
.
我检查了我在 grep
中使用的正则表达式,它按预期工作。我的语言环境是 en_US.UTF-8
。 GCC 和 Clang 产生相同的结果。
有什么我遗漏的吗?有没有办法 "tame" <regex>
所以它可以与西里尔字符一起使用?
西里尔字母在 UTF-8 中表示为多字节序列。因此,处理该问题的一种方法是使用名为 wstring
的 string
的 "wide" 版本。其他使用宽字符的函数和类型也需要替换为它们的 "multibyte-conscious" 版本,通常这是通过在它们的名称前加上 w
来完成的。这有效:
std::locale::global(std::locale("en_US.UTF-8"));
wstring s {L"Каждый охотник желает знать где сидит фазан."};
wregex re {L"[А-Яа-яЁё]+"};
for (wsregex_iterator it {s.begin(), s.end(), re}, end {}; it != end; it++) {
wcout << it->str() << "#";
}
输出:
Каждый#охотник#желает#знать#где#сидит#фазан#
(感谢@JohnDing 推介此解决方案。)
另一种解决方案是使用 regex::collate
使正则表达式对普通字符串敏感,请参阅 by @OlafDietsche for details. This topic 将阐明在您的情况下哪种解决方案更可取。 (结果在我的案例中 collate
是一个更好的主意!)
要使 А-Я
这样的范围正常工作,您必须使用 std::regex::collate
Constants
...
collate Character ranges of the form "[a-b]" will be locale sensitive.
将正则表达式更改为
std::regex re{"[А-Яа-яЁё]+", std::regex::collate};
给出了预期的结果。
根据源文件的编码,您可能需要在正则表达式字符串前加上 u8
std::regex re{u8"[А-Яа-яЁё]+", std::regex::collate};
我正在尝试使用标准 <regex>
库来匹配一些西里尔文字:
// This is a UTF-8 file.
std::locale::global(std::locale("en_US.UTF-8"));
string s {"Каждый охотник желает знать где сидит фазан."};
regex re {"[А-Яа-яЁё]+"};
for (sregex_iterator it {s.begin(), s.end(), re}, end {}; it != end; it++) {
cout << it->str() << "#";
}
但是,这似乎不起作用。上面的代码产生以下结果:
Кажд�#й#о�#о�#ник#желае�#зна�#�#где#�#иди�#�#азан#
而不是预期的:
Каждый#охотник#желает#знать#где#сидит#фазан
上面'��'符号的代码是1
.
我检查了我在 grep
中使用的正则表达式,它按预期工作。我的语言环境是 en_US.UTF-8
。 GCC 和 Clang 产生相同的结果。
有什么我遗漏的吗?有没有办法 "tame" <regex>
所以它可以与西里尔字符一起使用?
西里尔字母在 UTF-8 中表示为多字节序列。因此,处理该问题的一种方法是使用名为 wstring
的 string
的 "wide" 版本。其他使用宽字符的函数和类型也需要替换为它们的 "multibyte-conscious" 版本,通常这是通过在它们的名称前加上 w
来完成的。这有效:
std::locale::global(std::locale("en_US.UTF-8"));
wstring s {L"Каждый охотник желает знать где сидит фазан."};
wregex re {L"[А-Яа-яЁё]+"};
for (wsregex_iterator it {s.begin(), s.end(), re}, end {}; it != end; it++) {
wcout << it->str() << "#";
}
输出:
Каждый#охотник#желает#знать#где#сидит#фазан#
(感谢@JohnDing 推介此解决方案。)
另一种解决方案是使用
regex::collate
使正则表达式对普通字符串敏感,请参阅 collate
是一个更好的主意!)
要使 А-Я
这样的范围正常工作,您必须使用 std::regex::collate
Constants
...
collate Character ranges of the form "[a-b]" will be locale sensitive.
将正则表达式更改为
std::regex re{"[А-Яа-яЁё]+", std::regex::collate};
给出了预期的结果。
根据源文件的编码,您可能需要在正则表达式字符串前加上 u8
std::regex re{u8"[А-Яа-яЁё]+", std::regex::collate};