Perl正则表达式帮助(解析列)

时间:2011-03-26 01:24:54

标签: regex perl

我被困在这里。不知道为什么我的reg ex不起作用。我有一个管道分隔的文本文件与一系列列。我需要提取第3列。

文件:

A|B|C|D|E|F|G|H|I
2011-03-03 00:00:00.0|1|60510271|254735|27751|BBB|1|-0.1619023623|-0.009865904
2011-03-03 00:00:00.0|1|60510270|254735|27751|B|3|-0.0064786612|-0.0063739185
2011-03-03 00:00:00.0|1|60510269|254735|27751|B|3|-0.0084998226|-0.009244384

正则表达式:

$> head foo | perl -pi -e 's/^(.*)\|(.*)\|(.*)\|(.*)$/$3/g'

输出

-0.1619023623
-0.0064786612
-0.0084998226

显然没有输出正确的列。

想法?

6 个答案:

答案 0 :(得分:4)

通常,它更容易/更简单(KISS)不使用正则表达式来处理具有结构化分隔符的文件格式。只需将字符串拆分为“|”分隔符并获得第3个字段。

awk -F"|" '{print $3}' file

使用Ruby(1.9 +)

ruby -F"\|" -ane 'puts $F[2]' file

使用Perl,它类似于上面的Ruby one-liner。

perl -F"\|" -ane 'print $F[2]."\n"' file

答案 1 :(得分:1)

默认情况下,

.*会尽可能多地匹配,因此您的RE正在挑选最后三列(以及之前的所有内容)而不是第一列三(以及之后的一切)。您可以(至少)以两种方式避免这种情况:(1)代替.*,寻找[^|]*,或(2)让您的重复运算符不贪婪:.*?而不是.*

(或者您可以明确地拆分字符串,而不是将整个事物与单个RE匹配。您可能希望尝试这两种方法,看看哪种方法表现更好,如果重要。分裂可能会提供更长但更清晰的代码。)

答案 2 :(得分:1)

如何使用真正的解析器而不是将正则表达式拼凑在一起? Text::CSV应该完成这项工作。

my $csv = Text::CSV->new({sep_char => "|"});

答案 3 :(得分:1)

你需要让你的模式贪婪 - 所以:

's/^(.*?)\|(.*?)\|(.*?)\|(.*)$/$3/g'

答案 4 :(得分:1)

首先想到的是Text :: CSV(由Matt B提到),但如果数据看起来像我所说的那样split是正确的选择。

未测试:

$> head foo | perl -le 'while (<>) { print (split m{|})[2]; }'

如果你真的想要一个正则表达式,我会使用这样的东西:

s{^ [^\|]* \| [^\|]* \| ([^\|]*) \| .*$}{$1}gx;

答案 5 :(得分:0)

(?<=\|)\d{8}

对于(?<=\|)字符后跟8位数字,这可能会|正面显示