2017-01-09 52 views
3

我有這樣的一套代碼:包含特殊字符的字母順序perl的

use strict; 
use warnings; 
my %hash = (5328 => 'Adorable', 
       26191 => '"Giraffe"', 
       57491 => 'Is Very', 
       4915 => 'Cute',); 
foreach (sort { ($hash{$a} cmp $hash{$b}) || ($a cmp $b) } keys %hash) 
{ print "$hash{$_}\n"; } 

這將導致如下:

"Giraffe" 

Adorable 

Cute 

Is Very 

我需要它是按字母順序排列,而之前忽略的特殊字符AlphaNumeric字符喜歡在此示例中:

Adorable 

Cute 

"Giraffe" 

Is Very 

有什麼建議嗎?

+1

使用未加引號的字符串作爲鍵構建散列並對鍵進行排序。您還可以修改比較中的每個值。 –

+0

如果鍵是數字的,你可能想用'<=>'而不是'cmp'來進行二級排序。 –

+0

您的數據是錯誤的。您需要刪除引號,然後才能到達散列附近的任何位置。您是否正在處理CSV數據? – Borodin

回答

7

你可以簡單地做(請注意,我改變了第二cmp的班車運營<=>的數值)

foreach (sort { ($hash{$a}=~s/^\W+//r cmp $hash{$b}=~s/^\W+//r) || ($a <=> $b) } keys %hash) { 
    print "$hash{$_}\n"; 
} 

但是如果你有大量的數據,它的更好轉換您的數據(一勞永逸): 例如使用schwartzian變換:

my @result = map { $_->[2] } 
      sort { ($a->[0] cmp $b->[0]) || ($a->[1] <=> $b->[1]) } 
      map { [ $hash{$_}=~s/^"|"$//gr, $_, $hash{$_}] } keys %hash; 

print join "\n", @result; 
+4

你可能想提一提你需要Perl> = 5.14來使用'/ r'。 –

+0

作品很有魅力,謝謝! – Xavia

2

使用自定義排序功能可以去除要忽略的字符。

foreach (sort { 
      my ($aa,$bb) = ($hash{$a},$hash{$b}); 
      s/["]//g for $aa,$bb; # ignore " char. Add whatever else you want 
      $aa cmp $bb   # or lc($aa) cmp lc($bb) case-insensitive search 
       || $a cmp $b 
     } keys %hash) { ... } 
+0

您可以包含Schwartzian變換以使其更快。一直剝離的東西是昂貴的。 – simbabque

+1

是的,當輸入較大時,Schwartzian變換是值得的,而比較前的輸入變換很昂貴。 – mob

2

嘗試如下

use strict; 
use warnings; 
my %hash = (5328 => 'Adorable', 
     26191 => '"Giraffe"', 
     57491 => 'Is Very', 
     4915 => 'Cute',); 

foreach (sort{my ($one)=$hash{$a}=~m/([\w\s]+)/; my ($two)=$hash{$b}=~m/([\w\s]+)/; $one cmp $two} keys %hash) 
{ 
    print "$hash{$_}\n"; 
} 

組中的元素,並存儲到$one$two然後進行比較。

但是用@Casimir et Hippolyte答案很容易。他使用non-destructive modifier(r).,但它將支持5.14以上版本。

5

創建一個截斷特殊字符(在我的情況下爲truncate_special_chars)的函數。然後,在你的sort例程下使用它。

use strict; 
use warnings; 

my %hash = (
    5328 => 'Adorable', 
    26191 => '"Giraffe"', 
    57491 => 'Is Very', 
    4915 => 'Cute', 
    ); 


print join "\n", 
    map { $hash{$_ -> [0]} } 
    sort { $a -> [1] cmp $b -> [1] || $a -> [0] <=> $b -> [0] } 
    map { [ $_, truncate_special_chars($hash{$_}) ] } 
    keys %hash; 

sub truncate_special_chars { 
    my $str = shift; 
    $str =~ s/^\W//; 
    # may be use lc if you want case insensitive sort 
    return $str; 
} 

否則,你可以,如果你使用的是Perl >= 5.14使用/r

+0

您錯過了'$ hash {$ a} == $ hash {$ b}'的情況,它必須按鍵排序。 – Toto

+0

@Toto編輯。我想,這將是微不足道的,如果我帶着鑰匙而不是價值:)。 –

+0

我想你應該對散列鍵進行數值比較:'sort {$ a - > [1] cmp $ b - > [1] || $ a - > [0] <=> $ b - > [0]}'。 – jreisinger