shell - Unix区分大小写的UTF-8排序

标签 shell sorting unicode utf-8 collation

我发现了一个有关我的问题(shell - Different versions of UNIX sort handle case differently)的话题,但是可以这么说。

我已经弄乱了LANG变量,但似乎找不到能够实现我的目标的值。

举例说明:

abc a
Abc d
Abc b
abc e
abæ g


需要分类为:

abc a
abc c
Abc b
Abc d
abæ g


不是这个(这是我目前得到的):

Abc b
Abc d
abc a
abc c
abæ g


而且也不是这样(排序不区分大小写时得到的结果):

abc a
Abc b
abc c
Abc d
abæ g


换句话说:我希望每列都区分大小写,其中在第二个列中,同一单词的大写/小写版本中的首字母大写的单词不会排序,并且不会混在一起。

请注意,我需要UTF-8敏感排序(在这种情况下,我使用丹麦字母“æ”,它像这样放置在字母表中:“ ...vwxyzæøå”)。

我正在使用以下两列进行排序:

sort test.txt -k1,1 -k2,2


我有什么办法可以不借助脚本来做到这一点?

最佳答案

您不希望第一列中混合大小写的内容根据第二列中的内容混合在一起,但这正是不区分大小写的排序所提供的。它认为共享一个casefold的事物是相同的。

这组Unicode记录的种类:

abc a
Abc d
Abc b
abc e
abæ g


当然是这样的:

abæ g
abc a
Abc b
Abc d
abc e


这是因为在所有五行中,第一个字母和第二个字母都“相同”(即,它们的大小写相同),因此第一个不同的字母是第三个字母,这当然是在c之前出现的,这是另一个四个记录的第三个字母。

在其余各行中,它们都具有相同的前三个字母,因此,它们的第四个字母是主语,现在给出序列a,b,d,e。在Unicode排序中,空格(通常)并不重要,因为它是字母数字排序,而不是代码点排序。我们在这里只考虑字母,除非它们一直到大小写都是相同的,然后才考虑其他代码点。

这就是Unicode排序的工作方式。

除非您要求,否则Unicode排序算法不会关注丹麦语的排序。该代码点的默认DUCET条目将æ和å放在a旁,将ø放在o旁。 OED会按以下顺序对这些条目进行排序:

 allergist
 allergy
 Allerød
 allers
 allethrin


这是因为“Allerød”中的o在“变态反应”中紧随g,而在allers中则先于s。变音符号仅在其他条件相同的情况下才重要,因此假想的“变态反应”将在“Allerød”之前,假想的“变态反应”将在其之后,但变态反应在之前。

这就是Unicode中排序的工作方式。斯堪的纳维亚人讨厌它,因为他们认为它应该做他们特有的本国系统所做的任何事情,但是Unicode并不偏向于特定的语言。如果您想要白痴,则必须使用语言环境排序。要获得像这样的丹麦语言环境特定的排序:

abc a
Abc b
Abc d
abc e
abæ g


您需要使用指定的丹麦语言环境来运行排序,而不是以残破的POSIX方式,而是以Unicode方式。

首先,您必须放弃尝试使用sort(1)。变得更糟然后变得毫无用处:不可靠且具有欺骗性。如果您具有Unicode数据,则应该使用Unicode排序,无论是像OED一样未修改,还是针对您的小村庄进行了修改。

要产生普通的Unicode顺序,必须使用:

#!/usr/bin/env perl
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);


要获取按语言环境限制的非默认值,您需要:

#!/usr/bin/env perl    
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);


自Perl版本v5.6起,已包含Unicode::Collate模块的标准配置。
自从Perl v5.14发行以来,Unicode::Collate::Locale模块已成为标准组件,但可以从早期版本的CPAN轻松安装:

 $ sudo perl -MCPAN -e "install Unicode::Collate::Locale"


之所以必须使用Perl,是因为您根本不相信供应商的语言环境能够根据Unicode归类算法(不管是否进行语言环境修改)来工作。我从未见过两个不同的系统,它们以相同的方式工作,这意味着每对中至少有一个损坏了,也许两者都损坏了。相反,无论您身在何处,都可以保证UCA始终具有相同的行为方式。不管您的终端可以显示什么。它不在乎字体。不管您是否重定向。它不在乎您运行的是哪个Shell。不管您的格特鲁德姨妈是否碰巧在一个月的第5个星期一运行代码。它只是起作用,并且在每种情况下每次都以相同的方式起作用。使用UCA。不接受替代品。

但是,仅仅因为您使用UCA并不意味着您需要接受默认的订购。 UCA的设计非常适合剪裁。如果您要进行语言环境排序,这很容易-如果该语言环境有CLDR数据,那么它就显得微不足道了。如果您想做某种书名和电影名,或者想做那些姓氏比姓氏强,并且所有苏格兰Mc-和Mac-名字都在M-之前但彼此无关的人的名字,那么所有这些都是使用UCA非常非常容易。您可以想象的任何事情都可以做到,而且通常都非常容易。关键是,使用UCA,您总是会从一种行为开始,无论平台或偏见如何,它都可以保证以完全相同的方式工作。这意味着当您要对其应用自定义项时,可以依靠它的工作方式。没有那个保证,一切都会丢失。

您可以为符合UCA的here的Unix sort(1)程序进行预制的命令行替换(很好,有点类似)。它当然不做任何领域,但确实做得更多。

关于shell - Unix区分大小写的UTF-8排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8052022/

相关文章:

c# - Linq 自定义排序

unicode - 如果 Ascii 运算符是可定义的,为什么不可以定义 Unicode 符号?

bash - "sh runMyCode.sh"不以 "for n in {10..99}"格式循环

Bash 格式的十六进制字符串

c++ - 按最后一个元素对 vector 排序

MySQL 字符集转换

c++ - 在 C++ 中编码解码的 url

linux - shell 脚本 - 如何进行多次读取?

linux - shell 脚本 : Not able to traverse files using $HOME or ~ in the path

java - 如何使用 null 对集合进行排序并在之后反转列表?