从行中提取可选字段值

时间:2012-01-13 10:18:28

标签: regex linux unix text-processing

我有单独行的文本,每行都有类似CSV的格式:

SOME BUNCH OF TEXT, FIELD_A: 12, FIELD_B: 0.2321, FIELD_C: 12:10:08 2011/07/22, FIELD_D: 656

字段的顺序始终相同,但某些字段可能不存在。在感兴趣的字段之间可以有其他字段,例如,与上面的行相比,我也可以获得以下内容:

SOME BUNCH OF TEXT, FIELD_A: 12, NOT_INTERESTED: 235, FIELD_B: 0.2321, FIELD_C: 12:10:08 2011/07/22, FIELD_D: 656, FIELDS

作为处理此文本的结果,我希望有一个干净的CSV文件,我的字段一个接一个地指定:

12,0.2321,12:10:08 2011/07/22,656

如果某个字段不存在,那么我想简单省略值(例如FIELD_B不存在):

12,,12:10:08 2011/07/22,656

如何使用sed,perl或awk等命令执行此操作? 我尝试使用perl -pe 's/^.*?(FIELD_A: (.*?),)?.*?$/\2/'提取单个字段并失败 - 正则表达式只是忽略了我的字段,即使它出现

2 个答案:

答案 0 :(得分:2)

您可以将awk与关联数组一起使用,如下所示。遍历字段并在:上拆分它们。然后将键值对存储到关联数组中。最后打印出你想要的字段。

awk -F, '{
 split("",arr)
 for(i=1; i<=NF; i++){
   a=index($i, ":")
   if(a != 0){
     # split on first colon to get key-value pair
     key=substr($i,1,a-1)
     val=substr($i,a+1)

     # remove leading spaces from key and value
     gsub(/^ */,"",key)
     gsub(/^ */,"",val)

     # store in an associative array
     arr[key]=val
   }   
 }
 # print out the desired fields
 print arr["FIELD_A"]","arr["FIELD_B"]","arr["FIELD_C"]","arr["FIELD_D"]
}' data.txt

答案 1 :(得分:1)

这种方式怎么样(假设已知文件名):

#!/usr/bin/perl
use strict;
use warnings;

my @f = qw(FIELD_A FIELD_B FIELD_C FIELD_D);
while(my $line = <DATA>) {
    chomp $line;
    my @r;
    for(@f) {
        if ($line =~ /$_:\s*([^,]+)/) {
            push @r, $1;
        } else {
            push @r,'';
        }
    }
    print join(',',@r), "\n";
}
__DATA__
SOME BUNCH OF TEXT, FIELD_A: 12, FIELD_B: 0.2321, FIELD_C: 12:10:08 2011/07/22, FIELD_D: 656
SOME BUNCH OF TEXT, FIELD_A: 12, NOT_INTERESTED: 235, FIELD_B: 0.2321, FIELD_C: 12:10:08 2011/07/22, FIELD_D: 656, FIELDS
SOME BUNCH OF TEXT, FIELD_A: 12, NOT_INTERESTED: 235, FIELD_C: 12:10:08 2011/07/22, FIELD_D: 656, FIELDS

<强>输出:

12,0.2321,12:10:08 2011/07/22,656
12,0.2321,12:10:08 2011/07/22,656
12,,12:10:08 2011/07/22,656