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