Perl 和 Unix 如何以相同的顺序对 Unicode 字符串进行排序和排序?

Posted

技术标签:

【中文标题】Perl 和 Unix 如何以相同的顺序对 Unicode 字符串进行排序和排序?【英文标题】:How can Perl and Unix sort, order Unicode strings in the same sequence? 【发布时间】:2014-11-08 05:49:29 【问题描述】:

我试图让 Perl 和 GNU/Linux sort(1) 程序就如何对 Unicode 字符串进行排序达成一致。我正在使用LANG=en_US.UTF-8 运行sort。在 Perl 程序中我尝试了以下方法:

use Unicode::Collate$Collator = Unicode::Collate->new(); use Unicode::Collate::Locale$Collator = Unicode::Collate->new(locale => $ENV'LANG'); use locale

它们中的每一个都因以下错误而失败(来自 Perl 方面):

输入未排序:[----,] 位于 [($1] 之后 输入未排序:[...] 在 [&] 之后 输入未排序:[($1] 位于 [1] 之后

对我有用的唯一方法是为 sort 设置 LC_ALL=C,并在 Perl 中使用 8 位字符。但是,这样一来,Unicode 字符串就没有正确排序。

【问题讨论】:

你打电话给sort了吗? Unicode::Collat​​e 不会改变sort 的默认行为;您必须使用自定义比较功能。 实际的 Perl 代码(对于 8 位字符)位于 github.com/dspinellis/sgsh/blob/master/sgsh-merge-sum.pl。它旨在合并多个sort | uniq -c 调用的输出。 请注意sort 使用LC_COLLATE,而不是LANG 另见:***.com/questions/20226851/… 这是意料之中的。如果未定义,则优先级为 LC_COLLATE,如果未定义 LANG,则为 LC_ALL。见pubs.opengroup.org/onlinepubs/007908799/xbd/envvar.html 【参考方案1】:

我不能直接回答,但是我在获取一个简单的脚本来正确排序塞尔维亚拉丁文本时遇到了问题,我找到了https://www.perl.com/pub/2012/06/perlunicook-demo-of-unicode-collation-and-printing.html/,复制了他的设置(我的实际处理比他的简单得多),最后得到了正确的该语言和区域设置的字母排序。在https://www.perl.com/pub/2012/04/perlunicook-standard-preamble.html/ 的整套指南中,几乎任何人都需要了解 Unicode 语言排序。

我假设您想对希腊语进行排序。这是我从指南中复制和改编的一个非常简单的版本,排序正确。

# min required setup for trial sort
use utf8;
use v5.14; # for locale sorting and unicode_strings
use Unicode::Normalize;
use Unicode::Collate::Locale;
my @words = qw
        Η
        Ιθάκη
        σ'
        έδωσε
        το
        ωραίο
        ταξίδι.
        Χωρίς
        αυτήν
        δεν
        θάβγαινες
        στον
        δρόμο.
;
print "Unsorted: @words\n";
my $coll = Unicode::Collate::Locale->new( locale => "el_GR" );
my @sorted_words = $coll->sort(@words);
print "Sorted: @sorted_words\n";

【讨论】:

【参考方案2】:

使用 Unicode::Sort 或 Unicode::Sort::Locale 没有任何意义。您不是在尝试根据 Unicode 定义进行排序,而是在尝试根据您的语言环境进行排序。这就是use locale; 的用途。

我不知道您为什么没有从cmp 下的use locale; 获得所需的订单。

你可以处理解压后的文件。

for q in file1.uniqc file2.uniqc ; do
   perl -ne's/^\s*(\d+) //; for $c (1..$1)  print ' "$q"
done | sort | uniq -c

当然,它需要更多的临时存储空间,但你会得到你想要的顺序。


我发现一个案例 use locale; 没有导致 Perl 的 sort/cmp 给出与 sort 实用程序相同的结果。诡异的。

$ export LC_COLLATE=en_US.UTF-8

$ perl -Mlocale -e'print for sort  $a cmp $b  <>' data
(
($1
1

$ perl -MPOSIX=strcoll -e'print for sort  strcoll($a, $b)  <>' data
(
($1
1

$ sort data
(
1
($1

说实话,sort 实用程序很奇怪。


在 cmets 中,@ninjalj 指出怪异可能是由于未定义权重的字符造成的。在比较这些字符时,排序是不确定的,因此不同的引擎可能会产生不同的结果。重新创建确切顺序的最佳选择是使用 sort 到 IPC::Run3 实用程序,但听起来不能保证总是产生相同的顺序。

【讨论】:

我正在对 20GB 数据集的性能进行基准测试,所以我买不起次优的解决方案。您描述的案例正是我面临的问题类型。请注意,我不太关心将使用的特定语言环境,只要它可以合理地与 Unicode 字符串(例如 DUCET)一起工作,并且它与 sort(1) 和 Perl 的工作方式相同。 关于“我正在对 20GB 数据集进行性能基准测试”,那么结果如何? RE “它与 sort(1) 和 Perl 的工作方式相同”,这是真的吗?你真的需要使用sort 实用程序吗? Perl 不使用 UCA 进行排序,而 glibc 使用 ISO 14651? @ninjalj,我认为基于区域设置的排序是由系统文件定义的? (我多次听说机器上有损坏的语言环境。)

以上是关于Perl 和 Unix 如何以相同的顺序对 Unicode 字符串进行排序和排序?的主要内容,如果未能解决你的问题,请参考以下文章

Perl回调函数和闭包

在 Perl 中生成有效的 Unix 用户名和密码

如何使用 Perl 判断两个文件的内容是不是相同?

如果使用Perl不存在目录,我该如何创建目录?

如何在 Perl 中使用带有管道的 Unix/AIX find 命令?

如何对大量 csv 文件进行排序以按特定顺序读取它们?