C++ <;regex>;有西里尔文字方面的问题

C++ <;regex>;有西里尔文字方面的问题,c++,regex,locale,regular-language,cyrillic,C++,Regex,Locale,Regular Language,Cyrillic,我正在尝试使用标准的库来匹配一些西里尔语单词: // 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 {

我正在尝试使用标准的
库来匹配一些西里尔语单词:

  // 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() << "#";
  }
与预期不同的是:

  Каждый#охотник#желает#знать#где#сидит#фазан
《基本法》�' 上面的符号是
\321

我已经检查了我与
grep
一起使用的正则表达式,它可以正常工作。我的语言环境是
en_US.UTF-8
。GCC和Clang都产生相同的结果


我有什么遗漏吗?有没有办法“驯服”
,这样就可以处理西里尔字母?

西里尔字母在UTF-8中表示为多字节序列。因此,处理该问题的一种方法是使用名为
wstring
string
的“宽”版本。使用宽字符的其他函数和类型也需要替换为其“多字节意识”版本,通常这是通过在其名称前加上
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
使regex对普通字符串的区域设置敏感,有关详细信息,请参见@OlafDietsche。将阐明在您的情况下哪个解决方案可能更可取。(在我的例子中,
collate
是一个更好的主意!)

对于像
А-Я
这样的范围,要正常工作,必须使用

常数

格式“[a-b]”的collate字符范围将区分区域设置

将正则表达式更改为

std::regex re{"[А-Яа-яЁё]+", std::regex::collate};
给出了预期的结果


根据源文件的编码,可能需要在正则表达式字符串前面加上前缀


我不太确定,但你不应该使用
std::wstring
std::u32string
std::wregex
boost::u32regex
等等?你的字符串是utf-8编码的吗?@JohnDing你完全正确。使用
wstring
等实现了这一技巧。如果你不介意的话,我会用这一点知识很快回答我自己的问题。@undercatapplaudsMonica当然不会,请继续。这篇文章表明它可能与utf-8一起工作:我可以确认这是有效的,而且与使用wchars相比,它似乎是一个侵入性更小的解决方案,我对谷歌上点击次数如此之少感到惊讶。
regex::collate
Каждый#охотник#желает#знать#где#сидит#фазан#
std::regex re{"[А-Яа-яЁё]+", std::regex::collate};
std::regex re{u8"[А-Яа-яЁё]+", std::regex::collate};