【问题标题】:Perl - load records from file into hashPerl - 将文件中的记录加载到哈希中
【发布时间】:2012-03-17 09:45:09
【问题描述】:

是否可以将文件中的记录直接加载到哈希中?记录由 /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

【问题讨论】:

  • 你的 slurp 会生成两个文件内容的副本,最好写成my $string; {local $/; $string = &lt;DATA&gt;;}

标签: perl file hash records


【解决方案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);

【讨论】:

  • “包含空格的奇怪名称” 例如Santa FeSalt Lake CityBaton Rouge ...
  • @Borodin New YorkWashington D.C.Kuala Lumpur。是的,现在我能想到很多,但是当我写下答案时,我完全空白了。
【解决方案2】:

这会给你一个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);

【讨论】:

    【解决方案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;
    

    【讨论】:

    • 抱歉延迟回复,但感谢您抽出宝贵时间在这里回复。这是一个很好的答案,并且对我的 Perl 脚本有很大帮助,不仅在这个例子中,而且我也在解析其他文件。再次感谢。
    猜你喜欢
    • 2015-07-06
    • 2010-09-19
    • 2015-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    • 1970-01-01
    • 2019-02-19
    相关资源
    最近更新 更多