我有一个文件,我需要以下面的格式解析。 (所有分隔符都是空格):
field name 1: Multiple word value.
field name 2: Multiple word value along
with multiple lines.
field name 3: Another multiple word
and multiple line value.
我熟悉如何解析单行固定宽度文件,但是我很难理解如何处理多行。
答案 0 :(得分:8)
#!/usr/bin/env perl
use strict; use warnings;
my (%fields, $current_field);
while (my $line = <DATA>) {
next unless $line =~ /\S/;
if ($line =~ /^ \s+ ( \S .+ )/x) {
if (defined $current_field) {
$fields{ $current_field} .= $1;
}
}
elsif ($line =~ /^(.+?) : \s+ (.+) \s+/x ) {
$current_field = $1;
$fields{ $current_field } = $2;
}
}
use Data::Dumper;
print Dumper \%fields;
__DATA__
field name 1: Multiple word value.
field name 2: Multiple word value along
with multiple lines.
field name 3: Another multiple word
and multiple line value.
答案 1 :(得分:4)
固定宽度对我说unpack
。可以使用正则表达式进行解析并进行拆分,但unpack
应该是更安全的选择,因为它是固定宽度数据的正确工具。
我将第一个字段的宽度设置为12,将空间设置为13,这适用于此数据。您可能需要更改它。模板"A12A13A*"
表示“找到12个然后是13个ascii字符,后跟任意长度的ascii字符”。 unpack
将返回这些匹配的列表。此外,如果未提供字符串,unpack
将使用$_
,这就是我们在此处所做的。
请注意,如果第一个字段没有固定宽度,直到冒号,因为它似乎在您的示例数据中,您需要合并模板中的字段,例如“A25A *”,然后剥去结肠。
我选择数组作为存储设备,因为我不知道您的字段名称是否唯一。哈希将覆盖具有相同名称的字段。数组的另一个好处是它保留了文件中出现的数据顺序。如果这些事情无关紧要,快速查找更重要,请改用哈希。
<强>代码:强>
use strict;
use warnings;
use Data::Dumper;
my $last_text;
my @array;
while (<DATA>) {
# unpack the fields and strip spaces
my ($field, undef, $text) = unpack "A12A13A*";
if ($field) { # If $field is empty, that means we have a multi-line value
$field =~ s/:$//; # strip the colon
$last_text = [ $field, $text ]; # store data in anonymous array
push @array, $last_text; # and store that array in @array
} else { # multi-line values get added to the previous lines data
$last_text->[1] .= " $text";
}
}
print Dumper \@array;
__DATA__
field name 1: Multiple word value.
field name 2: Multiple word value along
with multiple lines.
field name 3: Another multiple word
and multiple line value
with a third line
<强>输出:强>
$VAR1 = [
[
'field name 1:',
'Multiple word value.'
],
[
'field name 2:',
'Multiple word value along with multiple lines.'
],
[
'field name 3:',
'Another multiple word and multiple line value with a third line'
]
];
答案 2 :(得分:2)
你可以这样做:
#!/usr/bin/perl
use strict;
use warnings;
my @fields;
open(my $fh, "<", "multi.txt") or die "Unable to open file: $!\n";
for (<$fh>) {
if (/^\s/) {
$fields[$#fields] .= $_;
} else {
push @fields, $_;
}
}
close $fh;
如果该行以空格开头,请将其附加到@fields
中的最后一个元素,否则将其推送到数组的末尾。
或者,啜饮整个文件并使用环视分割:
#!/usr/bin/perl
use strict;
use warnings;
$/=undef;
open(my $fh, "<", "multi.txt") or die "Unable to open file: $!\n";
my @fields = split/(?<=\n)(?!\s)/, <$fh>;
close $fh;
虽然这不是推荐的方法。
答案 3 :(得分:0)
您可以更改分隔符:
$/ = "\nfield name";
while (my $line = <FILE>) {
if ($line =~ /(\d+)\s+(.+)/) {
print "Record $1 is $2";
}
}