2012-02-27 8 views
4

ファイルから直接ハッシュにレコードをロードできますか?レコードは/ beginと/ endで区切られ、内容は固定されています。私が欲しいものPerl - ファイルからハッシュにレコードをロードする

は次のように読み込まハッシュです:

hash_city{London}{slurped_record}='/begin CITY London\n big\n England\n Sterling\n/end CITY' 
hash_city{Paris}{slurped_record}='/begin CITY\n Paris\n big\n France\n Euro\n/end CITY' 
hash_city{Melbourne}{slurped_record}='/begin CITY\n\n Melbourne\n big\n Australia\n Dollar\n hot\n/end CITY' 

私は、オフに行くとなどハッシュ内のレコードを処理することができます...(「slurped_record」エントリ理由は後で私が追加したいれます「国=イングランドなど

hash_city{London}{Country}='England' 

、などのロンドンを言うために新しいキーは私がズルズルの代わりに、ファイルライン・バイ・ラインを読むことによって、作品に何かを達成するために管理してきました。/開始のマッチング、構築しますレコード($ rec。= $ _)、そして/ endとのマッチングと処理。ちょっと混乱していて、次のようにPerlのアプローチよりエレガントな...

私のコードの試みは、これまでのところです:

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

my $string = do {local $/; <DATA>}; 
my %hash_city = map{$2=>$1} $string =~ /(\/begin\s+CITY\s+(\w+).+\/end\s+CITY)/smg; 
print Dumper(%hash_city); 

__DATA__ 
stuff 
stuff 
/begin CITY London 
    big 
    England 
    Sterling 
/end CITY 

stuff 
stuff 

/begin CITY 
    Paris 
    big 
    France 
    Euro 
/end CITY 
stuff 

/begin CITY 

    Melbourne 
    big 
    Australia 
    Dollar 
    hot 
/end CITY 

stuff 
+0

あなたの吸い込みは、ファイルの内容の2つのコピーを生成し、より良い私の$文字列 'として書かれています。 {ローカル$ /; $ string = ;} '。 – Borodin

答えて

3

は同様にあなたのプロセスを進め、他の方法で回避を表示する小さなプログラムを作りました。 )エレガントかどうかは分かりませんが、仕事が終わったと思います。 )

my %city_record; 

## we're going to process the input file in chunks. 
## here we define the chunk start marker, and make Perl to separate file input with it 
local $/ = "/begin CITY"; 

# ignoring anything before the first section starts 
scalar <DATA>; 

while (<DATA>) { 
    # throwing out anything after the section end marker 
    # (might be done with substr-index combo as well, 
    # but regex way was shorter and, for me, more readable as well) 
    my ($section_body) = m{^(.+)/end CITY}ms; 

    # now we're free to parse the section_body as we want. 
    # showing here pulling city name - and the remaining data, by using the split special case 
    my ($city, @city_data) = split ' ', $section_body; 

    # filling out all the fields at once 
    # (may seem a bit unusual, but it's a simple hash slice actually, great Perl idiom) 
    @{ $city_record{$city} }{qw/ size country currency misc /} = @city_data; 
} 

# just to test, use something of yours instead.) 
print Dumper \%city_record; 
+0

帰りに遅れて申し訳ありませんが、ここに返信いただきありがとうございます。これはすばらしい答えであり、この例だけでなく、他のファイルも含めて私のPerlスクリプトで多くの助けになりました。再度、感謝します。 – Chris

1

おそらくflip-flop operator/FROM/ .. /TO/を使用できます。正規表現をより読みやすくするために、別の区切り文字を使用することができます。私は以下のm#^/begin ...#を使用しています。ヘッダーと都市名の間に空白だけがあると仮定すると、都市名の抽出は簡単です。 \S(空白ではない)を使用しています。「Foo-Bar」や「St.Tropez」のように名前に英数字以外の名前の都市名がありません。

空白を含む都市名が見つかった場合は、都市名を見つけるためにより良い正規表現を見つける必要があります。私はそれを運動として残します。

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

my %hash; 
my $string; 
while (<DATA>) { 
    if (m#^/begin CITY# .. m#^/end CITY#) { 
     $string .= $_; 
     if (m#^/end CITY#) { 
      my ($city) = $string =~ m#^/begin CITY\s*(\S+)#; 
      $hash{$city}{slurp} = $string; 
      $string = ""; 
     } 
    } 
} 
$Data::Dumper::Useqq=1; 
print Dumper(\%hash); 
+0

*「サンタフェ」、「ソルトレークシティ」、「バトンルージュ」などの空白スペースを含む奇妙な名前... – Borodin

+0

@Borodin 'New York'、' Washington D.C.'、 'Kuala Lumpur'ええ、今私はそれらのトンを考えることができますが、私が答えを書いたとき、私は完全に空白になりました。 – TLP

0

これはあなたを与えるだろうhash with all cities and their properties

my %cities = map { 
    my($name, @data, %props) = (split ' '); 
    @props{qw(Size Country Currency Temperature)} = @data; 
    $name => \%props 
} $string =~ m| 
    ^/begin \s+ CITY 
    (.+?) 
    ^/end \s+ CITY 
|gsmx; 

print Dumper(\%cities); 
関連する問題