2013-02-04 77 views
3

我有一個.sql文件,我正在閱讀我的輸入。假設該文件包含以下內容輸入....如何在Perl中保留哈希的順序?

Message Fruits Fruit="Apple",Color="Red",Taste="Sweet"; 

Message Flowers Flower="Rose",Color="Red"; 

現在我已經寫了一個perl腳本生成此文件哈希..

use strict; 
use Data::Dumper; 

if(open(MYFILE,"file.sql")){ 
    my @stack; 
    my %hash; 
    push @stack,\%hash; 
    my @file = <MYFILE>; 
    foreach my $row(@file){ 
     if($row =~ /Message /){ 
      my %my_hash; 
      my @words = split(" ",$row); 
      my @sep_words = split(",",$words[2]); 

      foreach my $x(@sep_words){ 
       my($key,$value) = split("=",$x); 
       $my_hash{$key} = $value; 
      } 
      push @stack,$stack[$#stack]->{$words[1]} = {%my_hash}; 
      pop @stack; 
     } 
    } 
    print Dumper(\%hash); 
} 

我得到以下輸出..

$VAR1 = { 
      'Flowers' => { 
         'Flower' => '"Rose"', 
         'Color' => '"Red";' 
         }, 
      'Fruits' => { 
         'Taste' => '"Sweet";', 
         'Fruit' => '"Apple"', 
         'Color' => '"Red"' 
         } 
     }; 

現在這裏哈希不保留輸入讀取的順序。我希望我的哈希與輸入文件中的順序相同。 我發現了一些類似Tie :: IxHash的庫,但我想避免使用任何庫。可以幫助我解決任何人嗎?

+16

哈希本身不保存順序。如果您需要保留訂單,請查看使用數組來保持訂單。 – Joel

+3

你有什麼對CPAN模塊? – cjm

+0

對CPAN模塊沒有任何反應......只是試圖找到另一種方法來做到這一點......不使用任何庫。 – Maverick

回答

4

對於低鍵方法,您可以始終將鍵維護在一個有序的數組中。

foreach my $x(@sep_words){ 
    my($key,$value) = split("=",$x); 
    $my_hash{$key} = $value; 
    push(@list_keys,$key); 
} 

然後解壓,遍歷鍵

foreach my $this_key (@list_keys) { 
    # do something with $my_hash{$this_key} 
} 

但是,確實有,你依賴鍵陣列和哈希保持同步的問題。如果你不小心,你也可能無意中多次添加相同的密鑰。

+0

正確的做法 – Borodin

+1

@Borodin,不,不總是,它不提供一種好方法插入和刪除鍵 – ikegami

+0

是的,我不想在非常簡單的場景之外使用它,但在那些場合,我認爲這是用餐 –

2

散列是一組具有獨特的鍵的鍵 - 值對。一套永遠不會訂購。

數組是任何數量的標量序列。數組本身是有序的,但唯一性必須在外部執行。

這是我對你的問題:

#!/usr/bin/perl 

use strict; use warnings; 
use Data::Dumper; 

local $/ = ";\n"; 

my @messages; 

while (<DATA>) { 
    chomp; 
    my ($msg, $to, $what) = split ' ', $_, 3; # limit number of fragments. 
    my %options; 
    while($what =~ /(\w+) = "((?:[^"]++|\\.)*)" (?:,|$)/xg) { 
     $options{$1} = $2; 
    } 
    push @messages, [$to => \%options]; 
} 

print Dumper \@messages; 

__DATA__ 
Message Fruits Fruit="Apple",Color="Red",Taste="Sweet"; 
Message Flowers Flower="Rose",Color="Red"; 

我把消息轉換成一個數組,因爲它進行排序。另外,我不會用一堆我不需要的體操做怪異的體操。

我不拆對所有換行符,因爲你可以有引號值包含換行符。出於同樣的原因,我不會盲目地分割,=並使用明智的正則表達式。這可能是值得加入的錯誤檢測,如die if not defined pos $what or pos($what) != length($what);末(需要在正則表達式/c標誌),來看看我們實際處理一切還是被拋出循環過早。

這將產生:

$VAR1 = [ 
     [ 'Fruits', 
     { 
      'Taste' => 'Sweet', 
      'Fruit' => 'Apple', 
      'Color' => 'Red' 
     } 
     ], 
     [ 'Flowers', 
     {                 
      'Flower' => 'Rose',            
      'Color' => 'Red'             
     } 
     ] 
]; 

(與其他縮進,但是這無關緊要)。

有一個問題存在:該文件必須以新行終止,或者最後一個分號沒有被捕獲。

+0

這是不必要的複雜。 OP沒有提及任何有關包含換行符或轉義字符的值或包含多行記錄的數據。什麼是'[^「] ++'呢?此外,最終的結果是一個數據結構,必須搜索所需的條目,而不是隻能通過其密鑰訪問 – Borodin

+0

@Borodin沒錯,提到,但我認爲這個問題中的代碼並沒有完全想到;使用'split'時忘記數據的確切規格是一個常見錯誤,'++'防止回溯,但實際上並不需要。在任何情況下,刪除這些複雜性是微不足道的,但我不想回答可能有危險的代碼 – amon

3

喬爾有它正確的 - 你不能可靠地信任在Perl的哈希的順序。如果您需要某個訂單,則必須將您的信息存儲在一個數組中。