cmp 与 sort 一起使用无法解决这个问题;它没有编码的概念,只是按代码点、逐个字符进行比较,在许多语言中都有惊喜。使用Unicode::Collate。† 更多信息请参见this post,更多信息请参见this post by tchrist 和此perl.com article。
另一个问题是在 utf8 中正确读取(解码)输入和写入(编码)输出。确保处理标准流上的数据的一种方法是通过open pragma,您可以使用它设置“层”,以便在读取/写入数据时对输入和输出进行解码/编码。
一个例子
use warnings;
use strict;
use feature 'say';
use Unicode::Collate;
use open ":std", ":encoding(UTF-8)";
my $file = ...;
open my $fh, '<', $file or die "Can't open $file: $!";
my @lines = <$fh>;
chomp @lines;
my $uc = Unicode::Collate->new();
my @sorted = $uc->sort(@lines);
say for @sorted;
模块的cmp方法可用于单独比较(如果数据
例如,在一个复杂的数据结构中,而不仅仅是一个扁平的行列表)
my @sorted = map { $uc->cmp($a, $b) } @data;
其中$a 和$b 需要适当设置,以便从@data 中提取要比较的内容。
如果您在源中有 utf8 数据,则需要 use utf8,而如果您通过其他渠道(包括来自 @ARGV)接收 utf8,则可能需要手动 Encode::decode 这些字符串。
有关详细信息,请参阅链接的帖子(及其中的链接)和文档。有关更全面的信息,请参阅此perlmonks post。有关自定义排序,请参阅此 Effective Perler article。
† 示例:通过代码点比较 ä > b 而接受的德语订单是 ä b
perl -MUnicode::Collate -wE'use utf8; binmode STDOUT, ":encoding(UTF-8)";
@s = qw(ä b);
say join " ", sort { $a cmp $b } @s; #--> b ä
say join " ", Unicode::Collate->new->sort(@s); #--> ä b
'
所以我们需要使用Unicode::Collate(或自定义排序例程)。