【发布时间】:2010-12-13 05:33:44
【问题描述】:
这真的是一个双重问题,我的两个最终目标都有答案:
- 就机制而言,标准字符串比较顺序是什么?
- 有什么更好的名称可以让我更新文档?
sort 的 Perl 文档说,没有块,sort 使用“标准字符串比较顺序”。但是这个命令是什么?它应该有一个更好的名字。对于这个问题,我特指locale 无效的情况,因为它定义了它自己的顺序。
在过去的几年里,我们通常将标准排序顺序称为“按ASCII 顺序”。它在Learning Perl 和许多其他书籍中。但是,该术语已过时。 Perl 从 5.6 开始就支持 Unicode。谈论 ASCII 是老派。因为 Perl 也支持 Unicode,所以它知道字符串。在 sv.c 中,Perl_sv_cmp 知道 locale、bytes 和 UTF-8。前两个很容易。但我对第三个没有信心。
/*
=for apidoc sv_cmp
Compares the strings in two SVs. Returns -1, 0, or 1 indicating whether the
string in C<sv1> is less than, equal to, or greater than the string in
C<sv2>. Is UTF-8 and 'use bytes' aware, handles get magic, and will
coerce its args to strings if necessary. See also C<sv_cmp_locale>.
=cut
*/
当 Perl 使用 UTF-8 进行排序时,它真正排序的是什么?字符串编码的字节,它代表的字符(可能包括标记?),还是其他?我认为这是 sv.c 中的相关行(提交 7844ec1 的第 6698 行):
pv1 = tpv = (char*)bytes_to_utf8((const U8*)pv1, &cur1);
如果我没看错(使用我生锈的 C),pv1 被强制转换为八位字节,转换为 UTF-8,然后被转换为字符(在 C 意义上)。我认为这意味着它是按 UTF-8 编码排序的(即 UTF-8 用来表示代码点的实际字节)。另一种说法是它不对字素进行排序。我想我几乎已经说服自己我没看错,但你们中的一些人比我更了解这一点。
由此,下一个有趣的行是 6708:
const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);
在我看来,曾经有pv1 和pv2,它们被强制转换为char *,现在只是逐字节比较,因为它们被强制转换为void *。 memcmp 会发生这种情况吗,看起来它只是根据我迄今为止阅读的各种文档比较位?同样,我想知道我在从 bytes->utf8->char->bytes 的旅程中缺少什么,比如可能是 Unicode 规范化步骤。在 utf8.c 中查看 Perl_bytes_to_utf8 并不能帮助我回答这个问题。
作为旁注,我想知道这是否与Unicode Collation Algorithm 相同?如果是,为什么Unicode::Collate 存在?从表面上看,我不认为 Perl 的 sort 处理规范等价。
【问题讨论】:
-
有一种简单的方法可以查看它们是否按字节对 UTF-8 序列进行排序:如果这样做,您会得到 A
-
(自言自语)是的,这就是我在所有语言环境都设置为“C”时观察到的情况。似乎证实了你对源码的分析。
-
这不是我想观察的,这就是我要观察的。这种排序顺序从不与语言相关,即使对于英语也是如此(几十年来一直如此,早在 Unicode 之前)。我想它甚至存在的唯一原因是对所有字符串有一个总顺序,开销很小。话虽如此,您问题背后的真正问题是
cmp的默认行为,因为这决定了字符串的排序顺序。 -
我会问马库斯库恩:cl.cam.ac.uk/~mgk25/unicode.html
-
嗯,“自然”排序顺序是语言环境的用途,因为语言在字符顺序上存在分歧。 sort() 从来都不是关于自然秩序的,它展示了几十年的遗产和在 50 年代和 60 年代似乎正确的决定。先进技术的外星人可能永远不会造访像这样一个愚蠢的死水星球。 :)
标签: perl unicode sorting collation