规范的Unicode字符串形式

Canonical Unicode string form

本文关键字:字符串 Unicode      更新时间:2023-10-16

我有一个编码为UTF8的Unicode字符串。Unicode中的一个字符串可以有几个字节的表示形式。我想知道,是否存在或可以创建任何规范(规范化)形式的Unicode字符串——因此我们可以将这些字符串与memcmp(3)等进行比较。例如,ICU或任何其他C/C++库可以做到这一点吗?

您可能正在寻找Unicode规范化。本质上有四种不同的正规形式,每种形式都确保所有等价字符串之后都有一个共同的形式。然而,在许多情况下,您也需要考虑区域设置,因此,尽管这可能是一种进行字节对字节比较的廉价方法(如果您确保相同的Unicode转换格式,如UTF-8或UTF-16和相同的普通形式),但除了这种有限的用例外,它不会给您带来太多好处。

比较Unicode码点序列:

UTF-8本身就是一种规范表示。由相同Unicode代码点组成的两个Unicode字符串将始终被编码为完全相同的UTF-8字节序列,因此可以与memcmp进行比较。它是UTF-8编码的必要属性,否则它将不容易解码。但我们可以更进一步,这适用于所有官方的Unicode编码方案,UTF-8、UTF-16和UTF-32。它们将字符串编码为不同的字节序列,但总是将同一字符串编码为同一序列。如果考虑端序性和平台独立性,UTF-8是推荐的编码方案,因为在读取或写入16位或32位值时不必处理字节顺序。

因此,答案是,如果两个字符串使用相同的编码方案(例如UTF-8)和endiannes(UTF-8不是问题)进行编码,则得到的字节序列将是相同的。

比较Unicode字符串:

还有一个问题更难处理。在Unicode中,一些字形(你在屏幕或纸上看到的字符)可以用一个代码点或两个连续代码点的组合来表示(称为组合字符)。这通常适用于带有重音符号、变音符号等的字形。由于代码点表示的不同,它们对应的字节序列也会不同。在考虑这些组合字符的同时比较字符串不能用简单的字节比较来执行,首先必须对其进行规范化

其他答案提到了一些Unicode规范化技术、规范形式和库,您可以使用这些技术将Unicode字符串转换为正常形式。然后,您将能够将它们与任何编码方案逐字节进行比较。

您希望将字符串规范化为Unicode规范化形式之一。libicu可以为您做到这一点,但不能使用UTF-8字符串。您必须首先使用例如ucnv_toUChars将其转换为UChar,然后使用unorm_normalize进行规范化,再使用ucnv_fromUChars进行转换。我认为还有一些特定版本的ucnv_*用于UTF-8编码。

如果memcmp是您唯一的目标,那么您当然可以在unorm_normalize之后直接在UChar数组上执行此操作。