Perl - 将文件从文件加载到哈希

时间:2012-02-27 22:11:10

标签: perl file hash records

是否可以将文件中的记录直接加载到哈希中?记录以/ begin和/ end分隔,并具有固定的内容顺序。

我想要的是这样的哈希:

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'条目的原因是后来我想添加新密钥来表示伦敦,'country = England'等

hash_city{London}{Country}='England'

我已经设法通过啜饮而不是逐行读取文件来实现某些功能。匹配/ begin,构建记录($ 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

3 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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);

答案 2 :(得分: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);