我被困在这里。不知道为什么我的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
显然没有输出正确的列。
想法?
答案 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位数字,这可能会|
正面显示