我正在编写一个Perl脚本来运行并获取各种数据元素,例如:
1253592000
1253678400 86400 6183.000000
1253764800 86400 4486.000000
1253851200 36.000000 86400 10669.000000
1253937600 0.000000 86400 9126.000000
1254024000 0.000000 86400 2930.000000
1254110400 0.000000 86400 2895.000000
1254196800 0.000000 8828.000000
我可以抓住这个文本文件的每一行没问题。
我正在使用正则表达式来抓取每个字段。一旦我在一个变量中有一行,即$ line - 我怎样才能抓住每个字段并将它们放入自己的变量中,即使它们有不同的分隔符?
答案 0 :(得分:13)
此示例说明如何使用空格作为分隔符(split)或使用固定列布局(unpack)来分析行。使用unpack
如果您使用大写字母(A10等),则会删除空格。 注意:正如brian d foy指出的那样,split
方法对于缺少字段的情况(例如,第二行数据)不起作用,因为字段位置信息将迷路;除非我们误解您的数据,否则unpack
是前往此处的方式。
use strict;
use warnings;
while (my $line = <DATA>){
chomp $line;
my @fields_whitespace = split m'\s+', $line;
my @fields_fixed = unpack('a10 a10 a12 a28', $line);
}
__DATA__
1253592000
1253678400 86400 6183.000000
1253764800 86400 4486.000000
1253851200 36.000000 86400 10669.000000
1253937600 0.000000 86400 9126.000000
1254024000 0.000000 86400 2930.000000
1254110400 0.000000 86400 2895.000000
1254196800 0.000000 8828.000000
答案 1 :(得分:3)
使用my module DataExtract::FixedWidth
。对于在perl中使用Fixed Width列,它是功能最全,经过充分测试的。如果速度不够快,您可以传入unpack_string
,无需启发式检测边界。
#!/usr/bin/env perl
use strict;
use warnings;
use DataExtract::FixedWidth;
use feature ':5.10';
my @rows = <DATA>;
my $de = DataExtract::FixedWidth->new({
heuristic => \@rows
, header_row => undef
});
say join ('|', @{$de->parse($_)}) for @rows;
--alternatively if you want header info--
my @rows = <DATA>;
my $de = DataExtract::FixedWidth->new({
heuristic => \@rows
, header_row => undef
, cols => [qw/timestamp field2 period field4/]
});
use Data::Dumper;
warn Dumper $de->parse_hash($_) for @rows;
__DATA__
1253592000
1253678400 86400 6183.000000
1253764800 86400 4486.000000
1253851200 36.000000 86400 10669.000000
1253937600 0.000000 86400 9126.000000
1254024000 0.000000 86400 2930.000000
1254110400 0.000000 86400 2895.000000
1254196800 0.000000 8828.000000
答案 2 :(得分:0)
我不确定列名称和格式,但您应该可以使用Text::FixedWidth
根据自己的喜好调整此配方use strict;
use warnings;
use Text::FixedWidth;
my $fw = Text::FixedWidth->new;
$fw->set_attributes(
qw(
timestamp undef %10s
field2 undef %10s
period undef %12s
field4 undef %28s
)
);
while (<DATA>) {
$fw->parse( string => $_ );
print $fw->get_timestamp . "\n";
}
__DATA__
1253592000
1253678400 86400 6183.000000
1253764800 86400 4486.000000
1253851200 36.000000 86400 10669.000000
1253937600 0.000000 86400 9126.000000
1254024000 0.000000 86400 2930.000000
1254110400 0.000000 86400 2895.000000
1254196800 0.000000 8828.000000
答案 3 :(得分:-1)
您可以分割线条。看来您的分隔符只是空格?您可以按以下顺序执行操作:
@line = split(" ", $line);
这将匹配所有空格。然后,您可以通过$ line [0],$ line [1]等进行边界检查和访问每个字段。
Split也可以采用正则表达式而不是字符串作为分隔符。
@line = split(/\s+/, $line);
这可能会做同样的事情。
答案 4 :(得分:-1)
如果所有字段都具有相同固定宽度并使用空格格式化,则可以使用以下split
:
@array = split / {1,N}/, $line;
其中N
是该字段的含义。这将为每个空场产生一个空间。
答案 5 :(得分:-2)
固定宽度分隔可以这样完成:
my @cols;
my %header;
$header{field1} = 0; // char position of first char in field
$header{field2} = 12;
$header{field3} = 15;
while(<IN>) {
print chomp(substr $_, $header{field2}, $header{field3}); // value of field2
}
我的Perl非常生疏,所以我确信那里存在语法错误。但这就是它的要点。