在UTF-8编码下运行Ascii正则表达式处理非ASCII字符

12
#include <boost/regex.hpp>

#include <string>
#include <vector>
#include <iostream>

int main(int argc, char* argv[]) {

    std::string text = argv[1];
    std::string patterns = argv[2];

    boost::regex regex = boost::regex(patterns);

    boost::smatch match;

    std::cout << boost::regex_search(text, match, regex) << std::endl;    
}
如果我在输入字符串 hello¿ ¿(包含一个UTF-8编码的非ASCII字符)上运行程序,它返回 0 表示未找到,但如果我在输入字符串 hel√ √ 上运行它(再次包含非ASCII字符),它返回 1,表示找到了。
我的问题是:当使用utf字符时,boost::regex(即ascii版本)的预期行为是什么?
编辑:感谢所有评论,我仍然对为什么输出1感兴趣,因为文本和正则表达式都包含非ASCII字符。我猜测是字节被解释为ASCII,因此它们匹配。

1
你的“patterns”是什么? - Wiktor Stribiżew
1
这两个都在我的系统上打印出了1,这正是我所期望的。(我使用UTF-8区域设置,所以字符应该原样传递给程序。) - rici
在我的系统上,打印1也是如此。 - Amadeus
1
感谢所有的评论,我仍然对为什么只输出1感兴趣,因为文本和正则表达式都包含非ASCII字符。 我猜测是字节被解释为ASCII,因此它们匹配... - user695652
1
@user695652 你的猜测是正确的。例如, 的 UTF8 编码是 E2 88 9A,在 Latin-1 中被解释为 √。这里有一个有趣的问题,为什么你得到了 0 的结果,而 ¿ 的编码是 C2 BF,在 Latin-1 中被解释为 ¿。你能分享一些关于你的系统的细节,以及你如何调用命令的信息(即你如何 精确地 传递参数)吗? - Lucas Trzesniewski
显示剩余5条评论
2个回答

6
使用正则表达式处理ASCII字符串,是使用“字节”来查找模式。
在UTF-8字符串上使用正则表达式,则是在“多字节”序列上使用正则表达式,其中一个序列表示一个Unicode码点。

因此,正则表达式应用于使用可变字节计数的编码的Unicode字符串。

UTF-8字符串包含1到4个字节的多字节序列,表示一个Unicode“字符”。 在UTF-8中,只有ASCII 7位字符是1个字节“宽”。

因此,使用“ASCII正则表达式引擎”处理“UTF-8编码的字符串”,会忽略UTF-8编码的字符串中的多字节序列,并逐字节进行模式匹配。这种情况下,“ASCII正则表达式引擎”在“UTF-8编码的字符串”上的使用结果是无效的。

请查看http://utfcpp.sourceforge.net

要使正则表达式在UTF-8编码的字符串上工作,您需要:
  • 使用可与正则表达式一起使用的UTF-8字符串迭代器,或者
  • 使用std::codecvt_utf8结合临时设置全局区域设置以使正则表达式工作,或者
  • 将UTF-8编码的字符串转换为UTF-16编码的字符串以与基于std::wstring的Unicode正则表达式引擎一起使用。

regex_search函数返回一个布尔值,并在匹配时返回true
在您的情况下,ASCII正则表达式模式匹配了UTF-8编码字符串的一部分,该部分被解析为无效的ASCII字符串-正如您所假设的那样!
如果您在UTF-8编码的字符串中有英文文本,则可以安全地使用ASCII正则表达式引擎。超出ASCII 7位范围会使ASCII正则表达式引擎的结果不可靠。

0

这是一个漏洞而不是功能: 我在一个更好的系统上尝试了你的例子(Windows MinGW上的g++ 4.9.2),一切都很顺利:

#include <iostream>
#include <string>
#include <regex>
int main()
{ std::string text ="hello¿"; // or "hello√"
  std::string patterns ="¿";  // or "√"
  std::regex regex = std::regex(patterns);
  std::smatch match;
  std::cout << std::regex_search(text, match, regex) << std::endl;
}

输出结果为:

1

问题:您的源代码是否编译为UTF-8编码的源代码?因为我没有看到“text”的内容标记为UTF-8(u8“…”)。如果是这样,ASCI RE引擎将使用变量“text”中的“倒置问号”字节将模式中的两个字节(0xC2 0xBF)进行匹配。如果不是,则ASCII RE引擎将在变量“text”的内容中匹配ASCII字符0xBF。这两种变体都不会在变量“text”的内容中使用Unicode代码点\u00BF!是的 - ASCII RE引擎声称成功搜索模式,但未搜索正确的内容! - Martin Lemburg
@Martin:是的,我使用Eclipse,并且源代码采用UTF-8编码。 - Roland

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