2011-01-20 50 views
1

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可能不包含任何值,或包含空格的数据。所有固定的格式都是用空格(没有选项卡或其他特殊字符)完成的。澄清 - 列不一致大小。一个文件可能具有13个字符的COL4,另一个文件具有21个字符的COL4。或者不像另一个SO成员那样严格。

+0

可以一列从一个不同的每行之间的偏移开始?例如。 row1是`| 1 2 3 |`(3个空格),row2是`| 11111 2 3 |`(也是3个空格,但现在第二列的偏移量4比第一行大,因为第二行的第一个值很宽) – DVK 2011-01-20 20:58:44

+0

不,列大小对于每个数据行是一致的文件。可以区分文件,但在文件中保持一致。 – Walinmichi 2011-01-20 21:03:02

+0

列标题是否真的存在? – Svante 2011-01-20 21:04:35

回答

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阵列如你所愿,但他们将有领先的空间,你必须削减。

0

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

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

您可以使用一个很好的小正则表达式来裁剪空白。一个例子见Wikipedia

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 S IN的最后一行显示的列都是空格。

3

你需要弄清楚列的位置。作为一个真的挺恶心的黑客,你可以读取整个文件,然后串或线一起:那么

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

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

$ T将包含在只那里总是在列空格字符列空格字符;其他列将包含二进制垃圾。现在有了一个零宽度匹配拆分它的非空间相匹配:

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

实际上,我们希望宽度列生成解压缩()格式:

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

现在进程文件! :

​​3210

(此代码只被轻轻测试。)