在C++中使用UTF-8字符串正确检查回文

2022-05-17 00:00:00 c++ c++20

尝试回答问题How to use enqueu, dequeue, push, and peek in a Palindrome?时,我建议使用std::stringstd::string查找回文:

bool isPalindrome(const std::string str)
{
    return std::equal(str.begin(), str.end(), str.rbegin(), str.rend());
}

对于Unicode字符串,我建议:

bool isPalindrome(const std::u8string str)
{
    std::u8string rstr{str};

    std::reverse(rstr.begin(), rstr.end());

    return str == rstr;
}
我现在认为,当字符串中有多字节字符时,这会产生问题,因为多字节字符的字节顺序也颠倒了。此外,在不同的区域设置中,某些字符将彼此相同。因此,在C++20中:

  1. 如何对多字节字符进行可靠的比较?
  2. 当多个字符之间可能存在等价性时,如何在不同的区域设置中进行可靠的比较?

unicode

颠倒推荐答案字符串变得非常重要。从UTF-8转换为UTF-32/UCS-4是一个很好的开始,但仅有一个是不够的--Unicode还具有组合代码点,因此两个(或更多)连续的代码点形成一个单一的结果字素(添加的代码点将变音标记添加到基本字符),为了正常工作,您需要保持这些代码点的正确顺序。

因此,基本上不是代码点,您需要将输入划分为一系列字素,并颠倒字素的顺序,而不仅仅是代码点。

要处理代表相同字符序列的多个不同的代码点序列,通常需要进行标准化。有四种不同的归一化形式。在本例中,可能希望使用NFC或NFD(出于此目的,应该等效)。NFKC/NFKD形式主要是为了与其他字符集兼容,这听起来您可能不在乎。

不过,这也可能不是微不足道的。仅举一个众所周知的例子,考虑一下德语中的字符。这在某种程度上等同于";ss";,但只存在于小写形式,因为它从不出现在单词的开头。因此,像Ssa?这样的东西是否为回文可能存在争论空间(暂时忽略它实际上不是一个单词的小细节)。对于回文,大多数人忽略字母大小写,因此它会被忽略--但问题中的代码似乎将大小写视为重要的,在这种情况下,它可能不应该是重要的。

相关文章