在C++中使用UTF-8字符串正确检查回文
当试图回答一个问题时,如何在回文中使用入队、出队、推送和窥视?,我建议可以通过以下方式找到回文std::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 中:
- 你如何使多字节字符的比较健壮?
- 当多个字符之间可以等效时,如何使比较对不同的语言环境具有鲁棒性?
回答
反转 Unicode 字符串变得非常重要。从 UTF-8 转换为 UTF-32/UCS-4 是一个好的开始,但它本身是不够的——Unicode 也有组合码点,所以两个(或更多)连续的码点形成一个单一的结果字素(添加的代码point(s) add(s) 变音符号到基本字符),为了使事情正常工作,您需要以正确的顺序保留它们。
因此,基本上不是代码点,您需要将输入分成一系列字素,并颠倒字素的顺序,而不仅仅是代码点。
要处理表示相同字符序列的多个不同代码点序列,您通常需要进行规范化。有四种不同的归一化形式。在这种情况下,您可能想要使用 NFC 或 NFD(为此目的应该是等效的)。NFKC/NFKD 形式主要是为了与其他字符集兼容,这听起来您可能并不关心。
不过,这也很重要。举一个众所周知的例子,考虑德语字符“ß”。这有点等同于“ss”,但仅以小写形式存在,因为它永远不会出现在单词的开头。因此,对于类似的东西是否Ssaß是回文,可能存在争论的余地(暂时忽略它实际上不是一个词的小细节)。对于回文,大多数人会忽略字母大小写,因此它会是 - 但您在问题中的代码似乎将大小写视为重要,在这种情况下可能不应该如此。