什么是Perl的“标准字符串比较顺序”?

时间:2009-11-04 22:55:46

标签: perl unicode sorting collation

这真是一个双重问题,我的两个目标是:

  • 就机制而言,标准字符串比较顺序是什么?
  • 什么是更好的名称,以便我可以更新文档?

Perl的sort文档说,如果没有阻止,sort使用“标准字符串比较顺序”。但那顺序是什么?应该有一个更好的名称。对于这个问题,我特别指的是locale没有生效的情况,因为它定义了自己的顺序。

在过去的几年中,我们通常将标准排序顺序称为“ASCIIbetically”。它出现在Learning Perl和许多其他书籍中。但是,该术语已过时。自5.6以来,Perl一直是Unicode感知的。谈论ASCII是老派。由于Perl也支持Unicode,因此它知道字符串。在 sv.c 中,Perl_sv_cmp知道localebytes和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);

对我来说,一旦它pv1pv2被强制转换为char *,现在只是逐字节进行比较,因为它们被强制转换为{{1 }}。那是void *会发生什么,看起来它只是基于我到目前为止读过的各种文档来比较位?再一次,我想知道我在行程中从字节 - > utf8-&gt; char-&gt;字节中遗漏了什么,就像Unicode规范化步骤一样。在 utf8.c 中查看memcmp并没有帮助我回答这个问题。

作为旁注,我想知道这是否与Unicode Collation Algorithm相同?如果是,为什么Unicode::Collate存在?从它的外观来看,我不认为Perl的Perl_bytes_to_utf8处理规范等价。

2 个答案:

答案 0 :(得分:14)

UTF-8具有根据字节值逐字节地对UTF-8字符串进行排序的属性,与根据代码点编号对代码点进行排序的顺序相同。也就是说,我知道U + 2345的UTF-8表示在U + 1234的UTF-8表示后按字典顺序排列。

至于规范化,Perl核心对此一无所知;要在不同的表单中进行准确的排序和比较,您希望通过Unicode::Normalize运行所有字符串,并将它们全部转换为相同的规范化表单。我无法评论哪个最适合任何特定目的,主要是因为我没有线索。

此外,如果cmp编译指示正在使用,则排序和locale会受到影响;它使用POSIX整理顺序。使用use locale,8位语言环境和unicode是一个灾难的处方,但是使用use locale,UTF-8语言环境和unicode 应该有效地工作。我不能说我已经尝试过了。无论如何,perllocaleperlunicode都有大量信息。

答案 1 :(得分:5)

我无法回答整个问题,所以让我在一个方面进行磨练:

    const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);
  

...看起来一旦它pv1pv2被强制转换为char *,现在只是逐字节比较,因为它们被强制转换为{{1 }}。是void *

会发生什么

差不多。 memcmpmemcmp之间的主要差异是:

  1. strcmp会在看到strcmp(即NULL)后停止,而Perl允许标量嵌入'\0'
  2. NULL的运行速度通常比memcmp
  3. 快一点

    但除此之外,你会得到相同的结果。

相关问题