在第一列中混合大小写的内容会根据第二列而混合在一起,但是不希望出现这种情况,因此需要进行大小写敏感的排序。大小写不敏感的排序视为相同的那些共享一个折叠大小写的内容。
需要排序的Unicode记录集:
abc a
Abc d
Abc b
abc e
abæ g
当然,这当中就包括了以下内容:
abæ g
abc a
Abc b
Abc d
abc e
这是因为在这五行中,第一个和第二个字母都“相同”(即,它们的大小写折叠后是相同的),所以第一个不同的字母是第三个字母,当然是一个 æ,排在 c 前面,而其他四条记录的第三个字母正好是 c。
对于剩下的行,它们的前三个字母都相同,所以它们的第四个字母是决定性的,现在是 a、b、d、e 的顺序。空格在 Unicode 排序中通常不重要,因为它是字母数字排序而不是代码点排序。我们只考虑字母,除非它们一直到大小写都相同,只有在这种情况下才考虑其他代码点。
这就是 Unicode 排序的工作原理。
Unicode Collation Algorithm 不会注意丹麦排序,除非你要求它这样做。该代码点的默认 DUCET 条目将像æ和å这样的内容放在 a 旁边,ø 放在 o 旁边。OED 将这些条目按以下顺序排序:
allergist
allergy
Allerød
allers
allethrin
这是因为 "Allerød" 中的 o 排在 "allergy" 中的 g 之后,并紧随 allers 的 s。仅当其他一切相同时,变音符才有意义。因此,假设有一个 "alleroc",它将位于 "Allerød" 之前;而一个假设中的 "allerog" 将会跟随 "Allerød" 但在 "allers" 之前。
这只是 Unicode 编码中排序的工作原理。斯堪的纳维亚人讨厌它,因为他们认为它应该按照他们个性化的国家系统操作,但 Unicode 不偏向任何特定语言。如果你想使用本地化排序来获取类似丹麦的特定排序,可以这样做:
abc a
Abc b
Abc d
abc e
abæ g
你需要使用指定了丹麦语区域设置的排序,而不是使用破损的POSIX方法,而是使用Unicode方式。
首先,你必须放弃试图使用
sort(1)。它比无用还糟:不可靠而且欺骗性的。如果你有Unicode数据,你应该使用Unicode排序,无论是像OED一样未经修改的,还是为你的小村庄修改过的。
为了产生正常的Unicode排序,你必须使用:
use strict;
use warnings;
use open qw(:std :utf8);
use utf8;
use Unicode::Collate;
my @lines = <<'End_of_Lines' =~ /\S.*\S\n/g;
abc a
Abc d
Abc b
abc e
abæ g
End_of_Lines
my $collator = Unicode::Collate->new();
print $collator->sort(@lines);
要获取本地化限制的非默认排序,仅供您使用,您需要:
use strict;
use warnings;
use open qw(:std :utf8);
use utf8;
use Unicode::Collate::Locale;
my @lines = <<'End_of_Lines' =~ /\S.*\S\n/g;
abc a
Abc d
Abc b
abc e
abæ g
End_of_Lines
my $collator = Unicode::Collate::Locale->new(locale => "da");
print $collator->sort(@lines);
Unicode::Collate
模块自Perl v5.6版本起已经被包含在标准库中。
Unicode::Collate::Locale
模块自Perl v5.14版本起已经被包含在标准库中,但是在早期版本上它也可以通过CPAN轻松安装:
$ sudo perl -MCPAN -e "install Unicode::Collate::Locale"
您必须使用Perl是因为您不能简单地相信供应商的语言环境会按照Unicode排序算法工作,无论是否进行语言环境修改。我从未见过两个不同的系统以相同的方式工作,这意味着每对中至少有一个是错误的,也许两者都是。相比之下,您可以保证UCA在任何地方始终以相同的方式运行。它不关心您的终端可以显示什么,不关心字体,不关心您是否被重定向,不关心您正在运行哪个shell,也不关心您的Aunt Gertrude是否在月份的第5个星期一运行代码。它只管工作,并且在任何情况下都以相同的方式工作。使用UCA,没有替代品。
但是,仅仅因为您使用了UCA并不意味着您需要接受默认排序。 UCA旨在非常适应定制。如果您想要按语言环境排序,这很容易 - 如果该语言环境有CLDR数据,则非常简单。如果您想对书籍和电影标题进行排序,或者对人名进行排序,其中姓氏计数强于名字,所有苏格兰的Mc和Mac名称都排在M-之前,但彼此无关,所有这些都使用UCA非常容易实现。您可以想象的任何事情都可以做到,通常是非常容易的。重点是,使用UCA时,您始终从一个行为开始,无论平台或偏见如何,它都保证以完全相同的方式工作。这意味着当您想要应用自己的定制时,您可以依靠它的工作方式。如果没有这个保证,一切都将丧失。
您可以在此处获取Unix sort(1)程序的预制命令行替代品(好吧,有点像),该程序符合UCA规范here。当然,它不会处理字段,但它确实可以做更多事情。
Unicode::Collate
基类和Unicode::Collate::Locale
派生类可以在Perl 5.6及更早版本上运行超过十年。只是第二个类直到最近才成为标准。它使用CLDR数据。只需进行CPAN安装,您就会没问题了。 - tchrist