在非字母语言(例如亚洲语言)中,什么是排序?

34

我有一些代码,可以按对象属性对表格列进行排序。我意识到,在日语或中文(非字母语言)中,传递给排序函数的字符串会像字母语言一样进行比较。

以日本姓氏列表为例:

寿拘 (Suzuki)
松坂 (Matsuzaka)
松井 (Matsui)
山田 (Yamada)
藤本 (Fujimoto)

当我通过Javascript对上述列表进行排序时,结果如下:
寿拘 (Suzuki)
山田 (Yamada)
松井 (Matsui)
松坂 (Matsuzaka)
藤本 (Fujimoto)

这与日语音节表的排序不同,后者会按照语音顺序排列列表(就像日语词典一样):

寿拘 (Suzuki)
藤本 (Fujimoto)
松井 (Matsui)
松坂 (Matsuzaka)
山田 (Yamada)

我想知道的是:

  1. 在排序函数中,一个双字节字符是否真的与另一个字符进行比较?
  2. 这样的排序到底发生了什么?
  3. (额外加分)这样的排序结果是否有意义?在亚洲(和其他)语言中,排序的概念是否真的有效?如果是,那么这意味着什么,如何创建适用于这些语言的比较函数?

补充总结答案并得出结论:

首先,感谢所有参与讨论的人。这非常有益和有帮助。特别向bobinceLie RyanGumboJeffrey ZhengLarry K 表示感谢,因为他们进行了深入而周到的分析。我授予检查标记给Larry K,因为他指引我找到了一个解决方案,而我之前没有考虑到它,但我对每个有用的答案都点了赞。

共识似乎是:

  1. 中文和日文字符串按照Unicode编码点进行排序,其排序可能基于某种理由,对有知识的读者来说可能是可以理解的,但不太可能在帮助用户查找所需信息方面具有实际价值。

  2. 要使排序在语义或音系上有用,需要的比较函数过于繁琐,不值得考虑,特别是结果可能不尽如人意,而且比较算法必须针对每种语言进行更改。最好允许排序继续进行,甚至不尝试比较函数。

  3. 我在这里可能问错了问题。也就是说,我想得太局限,没有考虑到真正的问题不是如何使这些语言中的排序有用,而是如何为用户提供一个有用的方法来查找列表中的项目。西方人自动想到排序用于此目的,我也有这个问题。Larry K指向我一篇维基百科文章,建议过滤函数对亚洲读者可能更有用。这是我打算追求的,因为它至少与排序同样快速,客户端处理。我将保留列排序,因为它在西方语言中得到了很好的理解,并且任何语言的使用者都会发现日期和其他基于数字的数据类型的排序很有用。但我还将添加过滤机制,它对于任何语言的长列表都很有用。


1
+1 我觉得这非常有趣 - Josh Stodola
9个回答

25
在排序函数中,一个双字节字符是否会与另一个进行比较?
JavaScript 中本地的 String 类型基于 UTF-16 代码单元,这就是所比较的内容。对于基本多文种平面中的字符(这些都是),这与 Unicode 代码点相同。
在 Web 上下文中,“双字节”一词,例如 Shift-JIS 编码,没有任何意义:DOM 和 JavaScript 字符串本质上是 Unicode,浏览器接收到的编码页面中原始字节早已不存在。
这种排序结果有意义吗?
意义不大。Unicode 代码点不提供任何特定的排序方式……因为首先,并没有全球公认的排序方式。即使对于最基本的 ASCII 拉丁字符,也存在差异(例如关于 v 和 w 是否是同一字母,或者大写字母 i 的大小写形式是 I 还是 İ 等)。而 CJK 则比此更加复杂。
主要的 Unicode CJK 统一表意文字块恰好按照偏旁部首和笔画数的顺序排序(康熙字典顺序),这可能会有些用处。但如果使用其他 CJK 扩展块中的字符,或混合使用一些假名、罗马字等,则它们之间将没有任何有意义的排序方式。

Unicode联盟尝试定义一些通用的排序规则,但这很复杂,通常不会在语言层面上尝试。真正需要语言敏感排序能力的系统(如操作系统、数据库)倾向于拥有自己的排序方案。

这与日语音节的排序不同

是的。总体而言,处理汉字按音节精确排序是一个非常困难的任务,因为你必须猜测发音。JavaScript无法确定‘藤本’指的是‘Fujimoto’还是‘touhon’;这种事情需要内置深入的词典和仍然不可靠的启发式算法……这不是你想要构建到编程语言中的事情。


非常感谢您提供周到和全面的答案。请查看我问题的补充说明。 - Robusto
此外,你说得对,每个汉字的不同读音(音读和训读)使得在日语中实现类似于音序排序的目标几乎不可能。我没有想到这一点,但我应该想到的。 - Robusto

10
如果您想要比默认JS字符串排序更好的东西,可以在Javascript中实现Unicode Collation Algorithm。这可能会改善一些问题。尽管如Unicode文档所述:
排序不是统一的; 它因语言和文化而异:德国人、法国人和瑞典人以不同的方式排序相同的字符。它也可能因特定应用程序而异:即使在同一种语言中,字典的排序方式也可能与电话簿或书目录不同。对于东亚表意文字等非字母文字,排序可以是音标或基于字符外观。 维基百科文章指出,由于非字母文字的排序非常困难,现在的答案是通过输入字符而不是通过查看列表来轻松查找信息。
我建议您与应用程序的真正知识渊博的最终用户交谈,以了解他们希望它如何运作。排序中文字符的问题并不是您的应用程序所特有的。
此外,如果您不想在系统中实现排序,另一个解决方案是创建一个Ajax服务,将名称存储在MySql或其他数据库中,然后使用排序语句查找数据。

非常感谢您提供周到和全面的答案。请查看我问题的补充说明。 - Robusto

3
字符串按字符逐个比较,其中代码点值定义了顺序

字符串的比较使用序列的代码点值的简单字典排序。没有尝试使用Unicode规范中定义的更复杂、基于语义的字符或字符串相等性和排序定义。因此,根据Unicode标准规范相等的字符串可能会测试为不相等。实际上,该算法假定两个字符串已经处于规范化形式。

如果需要更多内容,则需要使用可以考虑排序规则的字符串比较。

非常感谢您提供思路清晰、全面的答案。请查看我问题的附录部分。 - Robusto

3
其他问题已经有人回答了,我来回答这个问题:
在为这些语言创建比较函数时,应该努力做到什么?
一种方法是创建一个可以“读取”字符的程序;也就是说,能够将汉字/日文汉字字符映射到它们的“发音”(拼音/平假名读音)。在最简单的情况下,这意味着需要一个将汉字/日文汉字映射到声音的数据库。当然,这比听起来更困难(双关语不是故意的),因为许多字符在不同的上下文中可能有不同的发音,并且中国有许多不同的方言需要考虑。
另一种方法是按笔画顺序排序。这意味着需要一个将汉字/日文汉字映射到它们的笔画的数据库。另一个问题:中文和日文使用不同的笔画顺序进行书写。但是,除了日本和中国之外,使用笔画顺序在单个文本内保持一致性更高,因为汉字/日文汉字字符几乎总是使用相同的笔画顺序书写,无论它们的含义如何或者它们如何被读取。类似的想法是按部首而不是普通笔画顺序排序。
第三种方法是按Unicode代码点排序。这很简单,并且始终提供无可争议的一致排序;但是,问题在于排序顺序对人类来说毫无意义。
最后一种方法是重新考虑对绝对排序的需求,并仅使用一些启发式方法根据用户的需求进行排序。例如,在购物车软件中,您可以根据用户的购买习惯或价格进行排序。这可以避免问题,但大多数情况下它有效(除非您正在编译字典)。
正如您注意到的那样,前两种方法需要创建一个巨大的一对多映射数据库,但它们仍然不总是给出有用的结果。第三种方法也需要一个庞大的数据库,但许多编程语言已经将此数据库内置到语言中。最后一种方法是一种启发式方法,可能最有用,但它们注定永远无法提供一致的排序(比前两种方法更糟糕)。

非常感谢您提供周到和全面的答案。请查看我问题的补充说明。 - Robusto

1

是的,字符会被比较。通常情况下,它们是基于它们的Unicode代码点进行比较的,但是在平假名和汉字之间存在很大的差异,这使得排序在日语中可能无用。(汉字从中文借来,但它们在中文中出现的顺序并不对应于表示相同意义的平假名的顺序)。有一些排序规则可以使一些字符“相等”以便进行比较,但我不知道是否有一种规则会认为一个汉字等同于组成其发音的平假名 - 特别是因为一个字符可以有多个不同的发音。

在中文、韩文或其他没有三种不同字母表(其中一种非常不规则)的语言中,这可能不是一个问题。


1
那些按照代码点值升序排列。对于人类读者来说,这显然没有任何意义。为日文设计一个合理的排序方案并非不可能,但是对汉字进行排序却很困难(部分原因是我们无法确定是否在处理日文还是中文),因此许多程序员都采用了这种解决方法。

1
许多编程语言中的普通字符串比较函数旨在确保字符串可以按照唯一顺序排序,以允许二分查找和重复检测等算法正常工作。要按照对人类读者有意义的方式对数据进行排序,必须知道数据代表什么。例如,在英语电影标题列表中,“El Mariachi”通常会按“E”排序,但在西班牙电影标题列表中,它将按“M”排序。应用程序需要超出字符串本身所包含的信息,以了解字符串应如何排序。

1
Q1(你能排序吗)和Q3(排序有意义吗)的答案从中国大陆的角度来看都是“是”。对于Q2(如何排序):
所有汉字都有明确的发音(有些是多音字),如pinyin所定义,按拼音排序更为常见(几乎所有的中文词典都是这样),因为没有歧义。具有相同发音的字符然后按笔画顺序排序。
多音字对排序提出了额外的挑战,因为它们的拼音通常取决于它们所在的单词(我听说日语字符可能更加复杂)。例如,字符“阿”在“阿姨”中发音为a(1),在“阿胶”中发音为e(1)。因此,如果您需要对单词或句子进行排序,则不能仅从每个项目中逐个查看一个字符。

非常感谢您提供周到和全面的答案。请查看我问题的补充说明。 - Robusto

0
回想一下,在JavaScript中,您可以传递一个函数到sort()中,通过实现自己的排序方式来实现对人类有意义的排序:

myarray.sort(function(a,b){

//根据两个字符串的比较返回0、1或-1

});


谢谢,但我已经知道如何在排序函数中比较两个字符串了。我想要的是,在比较两个双字节值时,比较应该追求什么,以便对语言读者有用。 - Robusto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接