【问题标题】:why the comparision of two strings in utf8 is not correct?为什么 utf8 中两个字符串的比较不正确?
【发布时间】:2011-08-22 10:54:32
【问题描述】:

我有两个词,它们都是 std::string 类型,它们是 unicode 词。它们是相同的,我的意思是当我将它们写入某个文件时,它们都具有相同的表示形式。但是当我调用 word1.compare(word2) 时,我没有得到正确的结果。为什么他们不一样? 或者我应该使用另一个函数而不是 compare 来比较两个 unicode 字符串? 谢谢

ifstream myfile;
    string term = "";
    myfile.open("homograph.txt");   
    istream_iterator<string> i(myfile);
    multiset<string> s(i, istream_iterator<string>());
    for(multiset<string>::const_iterator i = s.begin(); i != s.end(); i = s.upper_bound(*i))
    {           
        term = *i;      

    }


    pugi::xml_document doc;
    std::ifstream stream("words0.xml");
    pugi::xml_parse_result result = doc.load(stream);
pugi::xml_node words = doc.child("Words");

for (pugi::xml_node_iterator it = words.begin(); it != words.end(); ++it)
{       
        std::string wordValue = as_utf8(it->child("WORDVALUE").child_value());
        if(!wordValue.compare(term))
        {
        o << wordValue << endl;
        }
}

第一个词是“term”,第二个词是wordValue; as_utf8() 的重载函数是:

std::string wordNet::as_utf8(const char* str)
{
    return str;
} 

【问题讨论】:

  • “代表”是什么意思?两个字符串都打印相同的内容吗?因为这没有任何意义。 std::string 可以在里面有\0,如果两个字符串都有它并且在\0 之后它们不同,则预计compare 将返回false。向我们展示一些代码 + 示例(+ 文件以及如何打开/阅读它)。
  • 当你把它们写出来时,你使用的是什么字符集?
  • 其中一个词是波斯语单词,我将其写入某个文件并使用 istream_iterator(file) 读取它。另一个字符串是 pugixml::child_value() 的返回值,它基本上是 pugi::char_t* 类型,然后我将其转换为字符串 suing as_utf8
  • 我编辑了我的问题并在其中添加了一些细节

标签: c++ string compare


【解决方案1】:

在Unicode中(而UTF-8就是Unicode),存在composition的问题。像é 这样的标记可以用它自己的代码点来表示,也可以用代码点e 后跟´ 来表示。可能是一个使用预合成 (é) 编码,另一个使用分解 ()。两者通常以相同的方式显示。为避免此问题,应在其中一种组合类型上规范化字符串。

当然,可能还有另一个问题,但这是导致看起来相等的字符串不能比较相等的问题之一。 OTOH,如果您的文本没有 ASCII 以外的任何字符,这几乎不是问题。

比较字符串的正确方法是先将它们标准化。您可以在 Python 中使用 unicodedata 模块来执行此操作。

Unicode Standard Technical Appendix #15 详细描述了组成规范化

【讨论】:

    【解决方案2】:

    Unicode 比你想象的要复杂。有组合字符,不可见的代码点等等。如果两个字符串在打印时看起来相同,这并不意味着它们是逐字节相同的。

    要考虑到 Unicode 的所有复杂性,您需要使用支持 Unicode 的字符串库。一个这样的库是ICU。 C++ 标准库绝对不支持 Unicode。它可能可以正确计算 UTF-8 字符串中的字符数,但仅此而已。

    【讨论】:

    • 当我将单词放入文本文件并将文件保存为 utf8 时我没有问题,我认为问题在于我不知道它返回的函数 as-utf8() 到底是什么?
    • 没错,as_utf8() 不会神奇地将您手头的任何编码重新编码为 UTF-8。如果要将字符串重新编码为 UTF-8,则需要使用可以进行重新编码的库。
    【解决方案3】:

    尝试改用std::wstring

    【讨论】:

    • as-utf8() 函数的结果是字符串,我不能使用 as-wide() 函数,因为它需要不同的参数
    • mbstowcs() 原生字符的函数可能是你需要的。
    • wstring 不能神奇地解决任何问题。除了他需要将编码转换为 utf16 或 utf32 之外,复合字形的注意事项仍然存在
    • 我的问题是我无法将 std::string 转换为 std::wstring
    • @aliakbarian, std::wstring(mbstowcs(std::string.c_str()))(嗯,不完全是,只是为了展示一个想法)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多