比较utf-8编码字符串的两个字节[]与比较两个unicode字符串相同吗?

时间:2010-08-13 16:44:07

标签: c# unicode

我在关于utf-8的维基百科文章中找到了这个:

  

将UTF-8字符串排序为无符号字节数组将产生与基于Unicode代码点对它们进行排序相同的结果。

这会让我相信,为了进行比较(排序,二进制搜索等),比较utf-8编码字符串的两个字节数组(即逐字节,如memcmp)将得到与比较实际的unicode字符串。

这是真的吗?

6 个答案:

答案 0 :(得分:5)

是的,因为在UTF-8编码和Unicode代码点的序列字节之间存在一对一的映射。

但是,除了查看原始代码点之外,还有比较Unicode字符串的方法。如果您只是将代码点(或UTF-8字节)视为数字,那么您将错过特定于文化的比较逻辑。

要在.NET上正确实现特定文化的比较和排序,您应该使用标准的字符串比较函数。

答案 1 :(得分:5)

这取决于“比较实际的Unicode字符串”的含义。

如果您只是要比较代码点(作为32位数字)而不是UTF-8编码的代码点,那么答案是肯定的:这将得到相同的结果。从代码点到UTF-8编码字节的映射是一对一的。

如果要进行正确的Unicode字符串比较,而不是UTF-8的逐字节比较,答案是否定的。在Unicode中,可以有不同的方式来表示相同的字符。例如,é可以用(至少)两种方式表示:

  • U+00e9 (LATIN SMALL LETTER E WITH ACUTE)
  • U+0065 (LATIN SMALL LETTER E)后跟U+0301 (COMBINING ACUTE ACCENT)

正确编写的Unicode比较函数会认为这两者是相同的。

答案 2 :(得分:5)

它与代码点比较的代码点相同,也就是说不关注大小写折叠,文化排序,组合或除Unicode值之外的其他任何代码点。

在将字符串视为人类可读文本时,这是无用的,但有时您只是希望能够将字符串放入 排序,就像某些算法一样(二进制搜索就像你一样)说)需要一致的排序,但这种一致排序的细节并不重要。

重要的是要注意,.NET提供的字符串的序数比较适用于内部使用的UTF-16,维护代码点排序。如果我们比较一个只有字符U + FF61的字符串和一个只有字符U + 10002的字符串,那么.NET会将后者存储为代理对,即0xD800和0XDC02。

因此:

string.CompareOrdinal("\U0000ff61", "\U00010002");

string.Compare("\U0000ff61", "\U00010002", StringComparison.Ordinal);

返回值大于零,即使前者的代码点值低于后者(我使用\ U形式而不是\ u形式使其更清晰)。

如果“实际的unicode字符串”是指.NET UTF-16字符串,那么你的问题的答案是否定的,原因恰恰相反,导致你认为它可能有效。

答案 3 :(得分:3)

不,不是。

例如,可以写为单个代码点(U+00C0 LATIN CAPITAL LETTER A WITH GRAVE)或两个代码点(U+0041 LATIN CAPITAL LETTER A U+0300结合GRAVE ACCENT)。

两个表示应该比较相等,但是会有不同的字节编码。

答案 4 :(得分:1)

所有其他答案都讨论了正确/复杂的 Unicode 比较或代码点比较。

但是,您可能会关心另一种类型的比较,即代码单元比较。例如,这是经常使用的类型 in web platform specifications。我希望它出现在其他“WTF-16”上下文中,例如 Win32 API、Java 和 C#。

Code unit 比较不等同于按字节进行的 UTF-8 比较,因为代理代码单元不成对。正确的 Unicode 字符串(即代码点序列)不能包含未配对的代理;所有代理代码单元都是一对的一部分,它们共同构成一个代码点。但是许多语言,如 JavaScript、Java 和 C# 将允许这种不成对的代理。我们将这些语言中的字符串称为 "WTF-16 strings"

对于包含不成对代理的字符串,UTF-8 按字节比较不会与代码单元比较排序相同。

U+D800 应该在之后 U+10002

因为这些在 WTF-16 中解码为代码单元

0xFF61 > 0xD800 0xDC02

但 UTF-8 字节顺序比较与代码点顺序匹配:

0xEF 0xBD 0xA1 < 0xF0 0x90 0x80 0x81

所以,总结一下:如果出于某种原因,例如匹配网络标准,您需要代码单元排序而不是代码点排序,则不能简单地比较 UTF-8 字节This page from the ICU project 有更多背景。

答案 5 :(得分:0)

  

我在关于utf-8的维基百科文章中找到了这个:

     
    

将UTF-8字符串排序为无符号字节数组将产生与基于Unicode代码点对它们进行排序相同的结果。

  
     

这会让我相信,为了进行比较(排序,二进制搜索等),比较utf-8编码字符串的两个字节数组(即逐字节,如memcmp)将得到与比较实际的unicode字符串。

这完全取决于“实际Unicode字符串”的含义以及“比较”的含义。在.Net Framework中,字符串采用UTF-16形式的Unicode。 UTF-16字符串之间的简单二进制比较将比UTF-8和UTF-32(引用中引用的代码点版本)字符串之间的相同比较具有不同的排序顺序。

但任何这些事情的二元比较都不是很有用。您应该使用内置的文化感知比较。这是因为对于所有意图和目的而言,可以从不同的代码点序列构造两个字符串。内置的比较考虑了这些因素。