Perl Text Parsing - 固定的分隔结构正在发生变化

时间:2011-01-20 20:40:57

标签: perl

Perl专家 - 我试图解决我的问题是变成了很多代码,在PERL中似乎我正在接近这个问题。这是我的问题:

我有一个文本块(下面的例子),它可以在列数据之间有可变数量的空格。我使用的是一个简单的拆分,但现在的问题是列“代码”现在在数据中包含空格(我只考虑了最后一列中的空格)。似乎是不变的(尽管我无法访问或控制源结构)是列之间至少有3个空格(可能更多,但从不少)。

所以,我想说我的列分隔符令牌是“3个空格”,然后修剪每个中的数据以获得我的实际柱状数据。

COL0   COL1   COL2   COL3         COL4   COL5
   -      4    0.2      1       416489   463455 554
          1    0.9      1           E1   
   0      3    1.4     14   E97-TEST 1   
   -      1   97.5    396         PASS   Good

我只是想把这些值变成6个变量。

注意:COL0可能没有值。 COL4可能包含数据空间。 COL5可能不包含值,也不包含空格数据。所有固定格式都使用空格(没有制表符或其他特殊字符)。澄清一下 - 列的大小不一致。一个文件可能有COL4为13个字符,另一个文件有COL4,宽度为21个字符。或者不像另一个SO成员所说的那样严格。

4 个答案:

答案 0 :(得分:3)

您需要确定列的位置。作为一个非常恶心的黑客,您可以读取整个文件,然后将字符串或行组合在一起:

my @file = <file>;
chomp @file;

my $t = "";
$t |= $_ foreach(@file);
然后

$ t将在列中包含空格字符,只有该列中始终有空格字符;其他列将包含二进制垃圾。现在用一个匹配非空格的零宽度匹配来分割它:

my @cols = split /(?=[^ ]+)/, $t;

我们实际上希望列的 widths 生成unpack()格式:

@cols = map length, @cols;
my $format = join '', map "A$_", @cols;

现在处理文件! :

foreach my $line (@file) {
  my($field, $field2, ...) = unpack $format, $line;
  your code here...
}

(此代码仅经过轻微测试。)

答案 1 :(得分:2)

如果您正在处理严格的柱状数据,unpack可能是您想要的:

#!perl

use strict;
use warnings;
use 5.010;

use Data::Dumper;

my $data = <<EOD;
COL0   COL1   COL2   COL3         COL4   COL5
   -      4    0.2      1       416489   463455 554
          1    0.9      1           E1   
   0      3    1.4     14   E97-TEST 1   
   -      1   97.5    396         PASS   Good
EOD

my @lines = split '\n', $data;
for my $line ( @lines ) {
    my @values = unpack("a5 A7 A7 A7 A13 A*", $line);
    print Dumper \@values;
}

这似乎会根据您的意愿将您的值转储到@values数组中,但它们会有前导空格,您必须将其剪掉。

答案 2 :(得分:1)

我会使用两个传递:在第一个中,找到每行中有空格的字符列;然后,用这些索引拆分或解包。之后进行空白修剪。

你的例子:

COL0   COL1   COL2   COL3         COL4   COL5
   -      4    0.2      1       416489   463455 554
          1    0.9      1           E1   
   0      3    1.4     14   E97-TEST 1   
   -      1   97.5    396         PASS   Good

000011100001110000111000011100000000001110000000000

最后一行中的1显示哪些列都是空格。

答案 3 :(得分:0)

我知道CanSpice已经回答了(可能是一个更好的解决方案),但您可以使用“$ /”设置输入分隔符。这必须在局部范围(可能是子范围)中完成,因为它是一个全局变量,或者您可能会看到副作用。例如:

local $/ = "   ";
$input = <DATAIN>; # assuming DATAIN is the file-handler

您可以使用漂亮的小正则表达式修剪空白。有关示例,请参阅Wikipedia