Woo*_*ome 3 sorting unicode shell collation utf-8
我找到了一个关于我的问题的线程(shell - 不同版本的UNIX排序处理案例不同),但它给出了"相反"的答案.
我已经搞乱了LANG变量,但似乎无法找到实现我目标的值.
举例来说:
abc a
Abc d
Abc b
abc e
abæ g
Run Code Online (Sandbox Code Playgroud)
需要分类到:
abc a
abc c
Abc b
Abc d
abæ g
Run Code Online (Sandbox Code Playgroud)
不是这个(这是我目前得到的):
Abc b
Abc d
abc a
abc c
abæ g
Run Code Online (Sandbox Code Playgroud)
而不是这个(这是我在不区分大小写时得到的):
abc a
Abc b
abc c
Abc d
abæ g
Run Code Online (Sandbox Code Playgroud)
换句话说:我希望每列具有区分大小写的排序,其中大写起始字母的单词未在顶部排序,同一单词的大写/小写版本不会混合在一起,具体取决于第二列.
请注意,我需要UTF-8敏感排序(在这种情况下,我使用丹麦字母"æ",它放在字母表中,如下所示:"...vwxyzæøå").
我使用以下方法对两列进行排序:
sort test.txt -k1,1 -k2,2
Run Code Online (Sandbox Code Playgroud)
我可以用任何方式在不诉诸剧本的情况下做到这一点吗?
您不希望第一列中的混合大小写混合在一起,具体取决于第二列的内容,但这正是不区分大小写的排序所给出的.它认为共享案例折叠的事物是相同的.
这组Unicode记录的排序:
abc a
Abc d
Abc b
abc e
abæ g
Run Code Online (Sandbox Code Playgroud)
当然是这样的:
abæ g
abc a
Abc b
Abc d
abc e
Run Code Online (Sandbox Code Playgroud)
那是因为第一个和第二个字母在所有五行中都是"相同"(即它们的casefolds是相同的),所以第一个不同的字母是第三个,当然是c之前的c,这是另一个四个记录作为他们的第三个字母.
对于其余的行,它们都具有相同的前三个字母,因此它们是第四个字母是决定性的,现在给出序列a,b,d,e.空格(通常)在Unicode排序中不重要,因为它是字母数字排序而不是代码点排序.我们只考虑这里的字母,除非它们一直相同,只考虑其他代码点.
这就是Unicode的排序方式.
除非您要求,否则Unicode校对算法不会注意丹麦语的排序.该代码点的默认DUCET条目将æ和å旁边的内容放在a旁边,ø旁边.OED按此顺序对这些条目进行排序:
allergist
allergy
Allerød
allers
allethrin
Run Code Online (Sandbox Code Playgroud)
那是因为"Allerød"中的o遵循"过敏"中的g并且在allers中先于s.变音符号只有在其他一切都相同的情况下才有意义,所以假设的"过敏症"会出现在"Allerød"之前,假设的"过敏症"会跟随它而在"allers"之前.
这就是Unicode中的排序方式.斯堪的纳维亚人讨厌它,因为他们认为它应该只做他们特殊的国家系统所做的事情,但Unicode并不偏向某种语言.如果你想要你的idiotsyncrasies,你必须使用区域设置排序.要获得像这样的丹麦语区域特定类型:
abc a
Abc b
Abc d
abc e
abæ g
Run Code Online (Sandbox Code Playgroud)
您需要使用指定的丹麦语言环境运行排序,而不是以破坏的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);
Run Code Online (Sandbox Code Playgroud)
虽然要获得区域设置限制的非默认仅供您排序,但您需要:
#!/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);
Run Code Online (Sandbox Code Playgroud)
Unicode::Collate
自Perl发布v5.6以来,该模块已包含在标准中.该Unicode::Collate::Locale
模块自Perl版本v5.14起包含在标准中,但在早期版本中可以从CPAN中轻松安装:
$ sudo perl -MCPAN -e "install Unicode::Collate::Locale"
Run Code Online (Sandbox Code Playgroud)
您必须使用Perl的原因是因为您无法信任供应商区域设置根据Unicode排序算法工作,无论是否进行区域设置修改.我从未见过两种不同的系统,它们以相同的方式工作,这意味着每对中至少有一个被破坏,也许两者都是.相比之下,无论您身在何处,都可以保证UCA 始终以相同的方式运行.它并不关心您的终端可以显示什么.它不关心字体.它不关心你是否被重定向.它不关心你正在运行的shell.它并不关心你的格特鲁德姨妈是否恰好在一个月的第一个星期一运行代码.它只是工作,并且在每种情况下每次都以相同的方式工作.使用UCA.不接受任何替代品.
但仅仅因为您使用UCA并不意味着您需要接受默认排序.UCA的设计非常适合剪裁.如果你想要一个区域设置排序,这很容易 - 如果有该区域设置的CLDR数据,它是非常简单的.如果你想做一些书籍和电影片头,或者姓氏数量比姓氏更强的人名,以及所有苏格兰麦克和麦克风名字在M-之前排序,但无论彼此如何,所有这些都是UCA非常容易.您可以想象的任何事情都可以完成,并且通常非常容易.重点是,对于UCA,您总是从一种行为开始,无论平台或偏见如何,都保证以完全相同的方式工作.这意味着当您想要将自己的自定义应用于它时,您可以依赖它的工作方式.没有这种保证,一切都会丢失.
你可以得到一个预制的命令行更换(当然,那种)为Unix的种类(1)程序,它是UCA兼容这里.它当然没有做领域,但确实做了很多.