代码之家  ›  专栏  ›  技术社区  ›  Eloff

比较UTF-8编码字符串的两个字节[]是否与比较两个Unicode字符串相同?

  •  8
  • Eloff  · 技术社区  · 15 年前

    我在维基百科关于UTF-8的文章中发现了这一点:

    将UTF-8字符串排序为无符号字节数组将产生与基于Unicode码位对其排序相同的结果。

    这将使我相信,为了比较(排序、二进制搜索等)的目的,比较UTF-8编码字符串的两个字节数组(即,像memcmp这样的字节数组)将得到与实际Unicode字符串相同的结果。

    这是真的吗?

    5 回复  |  直到 15 年前
        1
  •  5
  •   Thomas    15 年前

    这取决于您所说的“比较实际的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
  •   Tim Robinson    15 年前

    是的,假设在UTF-8编码的序列字节和Unicode码位之间有一对一的映射。

    但是,除了查看原始代码点之外,还有一些方法可以比较Unicode字符串。如果您只是将代码点(或UTF-8字节)看作数字,那么您会错过特定于区域性的比较逻辑。

    为了正确实现特定区域性的比较和排序,在.NET上,应该使用标准的字符串比较函数。

        3
  •  5
  •   Jon Hanna    15 年前

    它与用于代码点比较的代码点相同,也就是说,它不关注大小写折叠、文化顺序、组合或除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字符串,那么问题的答案是“否”,原因与导致您认为它可能有效的原因相反。

        4
  •  3
  •   SLaks    15 年前

    不,不是。

    例如, À 可以作为单个代码点写入( U+00C0 拉丁文大写字母A随以抑音符)或作为两个码点( U+0041 拉丁文大写字母A U+0300 结合重音符)。

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

        5
  •  0
  •   Jeffrey L Whitledge    15 年前

    我在维基百科关于UTF-8的文章中发现了这一点:

    将UTF-8字符串排序为无符号字节数组将产生与基于Unicode码位对其排序相同的结果。

    这将使我相信,为了比较(排序、二进制搜索等)的目的,比较UTF-8编码字符串的两个字节数组(即,像memcmp这样的字节数组)将得到与实际Unicode字符串相同的结果。

    这完全取决于您所说的“实际Unicode字符串”和“比较”的含义。在.NET框架中,字符串采用Unicode的UTF-16格式。UTF-16字符串之间的简单二进制比较与UTF-8和UTF-32(引号中引用的代码点版本)字符串之间的相同比较会产生不同的排序顺序。

    但是二元比较这些东西并不是很有用。您应该使用内置的具有文化意识的比较。这是因为对于所有意图和目的而言,可以从不同的代码点序列构造相同的两个字符串。内置比较将这些因素考虑在内。