2017-10-07 15 views
1

私はPerlでアルファベット順に配列をソートする方法を見つけようとしています。Perlのutf8文字列に "sort"を使用する

# List of countries (kept like this to keep clean, as its re-used in other places) 
    my $countries = { 
     'AT' => "íAustria", 
     'AU' => "Australia", 
     'BE' => "Belgium", 
     'BG' => "Bulgaria", 
     'CA' => "Canada", 
     'CY' => "Cyprus", 
     'CZ' => "Czech Republic", 
     'DK' => "Denmark", 
     'EN' => "England", 
     'EE' => "Estonia", 
     'FI' => "Finland", 
     'FR' => "France", 
     'DE' => "Germany", 
     'GB' => "Great Britain", 
     'GR' => "Greece", 
     'HU' => "Hungary", 
     'IE' => "Ireland", 
     'IT' => "Italy", 
     'LV' => "Latvia", 
     'LT' => "Lithuania", 
     'LU' => "Luxembourg", 
     'MT' => "Malta", 
     'NZ' => "New Zealand", 
     'NL' => "Netherlands", 
     'PL' => "Poland", 
     'PT' => "Portugal", 
     'RO' => "Romania", 
     'SK' => "Slovakia", 
     'SI' => "Slovenia", 
     'ES' => "Spain", 
     'SE' => "Sweden", 
     'CH' => "Switzerland", 
     'SC' => "Scotland", 
     'UK' => "United Kingdom", 
     'US' => "USA", 
     'TK' => "Turkey", 
     'NO' => "Norway", 
     'MX' => "Mexico", 
     'IL' => "Israel", 
     'IN' => "India", 
     'IS' => "Iceland", 
     'CN' => "China", 
     'JP' => "Japan", 
     'VN' => "áVietnamí" 
    }; 
    # Populate the original loop with "name" and "code" 
    my @country_loop_orig; 
    print $IN->header; 
    foreach (keys %{$countries}) { 
     push @country_loop_orig, { 
     name => $countries->{$lang}->{$_}, 
     code => $_ 
     } 
    } 

    # sort it alphabetically 
    my @country_loop = sort { lc($a->{name}) cmp lc($b->{name}) } @country_loop_orig; 

これは英語バージョンで正常に動作します:ここで私は何を英語で正常に動作している必要がありさ

Australia 
Austria 
Belgium 
Bulgaria 
Canada 
China 
Cyprus 
Czech Republic 
Denmark 
England 
Estonia 
Finland 
France 
Germany 
Great Britain 
Greece 
Hungary 
Iceland 
India 
Ireland 
Israel 
Italy 
Japan 
Latvia 
Lithuania 
Luxembourg 
Malta 
Mexico 
Netherlands 
New Zealand 
Norway 
Poland 
Portugal 
Romania 
Scotland 
Slovakia 
Slovenia 
Spain 
Sweden 
Switzerland 
Turkey 
United Kingdom 
USA 
Vietnam 

...しかし、あなたがしようとすると、このようなIEOなどとしてUTF8でそれを行う際に、動作しません:

Australia 
Belgium 
Bulgaria 
Canada 
China 
Cyprus 
Czech Republic 
Denmark 
England 
Estonia 
Finland 
France 
Germany 
Great Britain 
Greece 
Hungary 
Iceland 
India 
Ireland 
Israel 
Italy 
Japan 
Latvia 
Lithuania 
Luxembourg 
Malta 
Mexico 
Netherlands 
New Zealand 
Norway 
Poland 
Portugal 
Romania 
Scotland 
Slovakia 
Slovenia 
Spain 
Sweden 
Switzerland 
Turkey 
United Kingdom 
USA 
áVietnam 
íAustria 

これはどのように実現しますか? Sort::Naturally::XSが見つかりましたが、動作させることができませんでした。

+2

'cmp'は、文字セットとエンコーディングについては何も知りません。文字(文字列要素)を文字(文字列要素)の比較でまっすぐにします。 (おそらく 'use locale 'の下では使用しないでください。) – ikegami

答えて

6

Unicode::Collateがこれに役立ちます。

use warnings; 
use strict; 
use feature 'say'; 

use Unicode::Collate; 

use open ":std", ":encoding(UTF-8)"; 

open my $fh, '<', "country_list.txt"; 
my @list = <$fh>; 
chomp @list; 

my $uc = Unicode::Collate->new(); 
my @sorted = $uc->sort(@list); 

say for @sorted; 

しかし、非ASCII文字が非常に特定の受け入れ配置を有していてもよく、いくつかの言語で、あなたの最後のリストをソートし、質問がどんな詳細を提供しない簡単な例。おそらくUnicode::Collate::Localeが役に立ちます。

(試験)this perl.com articleおよびthis post(T.クリスチャンセン)およびthis effectiveperler articleを参照のこと。


複雑なデータ構造であることにより、データをソートする場合は、cmp方法は、個々の比較のためにある

my @sorted = map { $uc->cmp($a, $b) } @list; 
+0

素晴らしい、ありがとう。配列内でハッシュをソートするにはどうすればいいですか?たとえば、 '$ a - > {name} cmp $ b - > {name}'を実行していますか? –

+0

ところで、名前の配列だけをソートすると(ハッシュ構造を持たずに)、これは完全に機能します。私はデータストレージをどうやって再構築することができると思いますが、それをやり遂げる前にもっと良い方法があるかどうかを確認します:) –

+1

@AndrewNewby 'cmp'メソッドを使うと、' @s = sort { $ uc-> cmp($ a、$ b)} @list; '、個々の比較の場合 – zdim

関連する問題