对UTF-8输入进行排序

时间:2018-03-10 23:40:18

标签: perl utf-8

我需要从文件中对行进行排序,保存为UTF-8。这些行可以以西里尔字母或拉丁字符开头。我的代码在西里尔字母上运行错误。

sub sort_by_default  {
    my @sorted_lines = sort {
        $a <=> $b
          ||
        fc( $a) cmp fc($b)
     } @_;
}

3 个答案:

答案 0 :(得分:10)

cmp一起使用的sort对此无效;它没有编码的概念,只是通过代码点,逐个字符,以及许多语言中的惊喜进行比较。使用Unicode::Collate通过tchrist和this post更多地了解this post以及更多perl.com article

另一个问题是正确读取(解码)utf8中的输入和写入(编码)输出。确保处理标准流数据的一种方法是通过open pragma,您可以使用Encode::decode设置“层”,以便在读取/写入数据时对输入和输出进行解码/编码。

总而言之,一个例子

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,则可能需要手动perlmonks post这些字符串。

请参阅链接的帖子(及其中的链接)和文档以获取更多详细信息。有关详细信息,请参阅此EffectivePerler article。有关自定义排序,请参阅此{{3}}。

示例:通过代码点比较ä&gt; b,而德语中接受的订单为ä&lt; 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(或自定义排序例程)。

答案 1 :(得分:2)

要打开保存为UTF-8的文件,请使用适当的图层:

open my $FH, '<:encoding(UTF-8)', 'filename' or die $!;

不要忘记为输出设置相同的图层。

#! /usr/bin/perl
use warnings;
use strict;

binmode *DATA, ':encoding(UTF-8)';
binmode *STDOUT, ':encoding(UTF-8)';
print for sort <DATA>;

__DATA__
Борис
Peter
John
Владимир

答案 2 :(得分:1)

在Perl中正确处理UTF-8的关键是确保Perl知道信息的某个源或目标是UTF-8。根据您获取信息的方式不同,这样做会有所不同。如果UTF-8来自输入文件,则打开文件的方式是:

open( my $fh, '<:encoding(UTF-8)', "filename" ) or die "Cannot open file: $!\n";

如果您要在脚本源中包含UTF-8,请确保您拥有:

use utf8;

在剧本的开头。

如果您要从STDIN获取UTF-8字符,请在脚本开头使用此字符:

binmode(STDIN, ':encoding(UTF-8)');

STDOUT使用:

binmode(STDOUT, ':encoding(UTF-8)');

另外,请务必阅读UTF-8 vs. utf8 vs. UTF8以了解每个编码名称之间的区别。 utf8UTF8将允许有效的UTF-8和无效的UTF-8(根据第一个UTF-8提议的标准),并且不会抱怨无效的代码点。 UTF-8将允许有效的UTF-8,但不允许无效的代码点组合;它是utf-8-strict的简称。您还可以阅读问题How do I sanitize invalid UTF-8 in Perl?

最后,在@zdim建议后,您可以在脚本的开头使用:

use open ':encoding(UTF-8)';

其他变体如here所述。这将为未明确指定图层的所有open指令设置编码层。