使用unix实用程序在同一行中匹配多个模式

时间:2013-09-19 22:07:52

标签: regex awk grep

我正在尝试找到这种模式匹配。我想匹配并仅显示同一行中的第一个匹配项。其中一个匹配,第四个字段可以匹配两个模式中的任何一个,即; A,BCD.EF或AB.CD。一个例子是

Example 1:
12:23 23:23 ASDFGH 1,232.00 22.00
21:22 12:12 ASDSDS 22.00 21.00 

预期输出为

Expected Result 1:
12:23 ASDFGH 1,232.00
21:22 ASDSDS 22.00

使用我对grep和stackoverflow的一点知识,我已经做到了这一点。

< test_data.txt grep -one "[0-9]/[0-9][0-9]\|[0-9]*,[0-9]*.[0-9][0-9]\|[0-9]*.[0-9][0-9]" | awk -F ":" '$1 == y { sub(/[^:]:/,""); r = (r ? r OFS : "") $0; next } x { print x, r; r="" } { x=$0; y=$1; sub(/[^:]:/,"",x) } END { print x, r }'

任何使这更简单或更清洁并实现完整功能的想法。

更新1:其他几个例子可能是:

Example 2:
12:21 11111 11:11 ASADSS 11.00 11.00
22:22 111232 22:22 BASDASD 1111 1,231.00 1,121.00
  1. 某些行可能会有更多字段。
  2. 字段的顺序也不一定保留。我可以通过单独处理具有不同顺序的文件或以某种方式将它们转换为此顺序来解决这个问题。所以这种情况可以放松。
  3. 更新2:似乎某种程度上我的问题不明确。因此,查看它的一种方法是查找:我在一行上找到的第一个“时间”,第一组字母数字字符串和第一个带/不带逗号的十进制值,所有这些都打印在同一输出上线。更一般的描述是,给定输入行,在输出中的一行中打印模式1的第一次出现,模式2的第一次出现和模式3的第一次出现(其本身是“或”两种模式)必须是稳定的(即;保持它们在输入中出现的顺序)。对不起,这是一个有点复杂的例子,我也试图了解这是否是使用Unix实用程序为Perl / Python等完整语言留下的最佳位置。所以这是第二组例子的预期结果。

    Expected Result 2:
    12:21 ASADSS 11.00
    22:22 BASDASD 1,231.00
    

2 个答案:

答案 0 :(得分:3)

#!/usr/bin/awk -f

BEGIN {
    p[0] = "^[0-9]+:[0-9]{2}$"
    p[1] = "^[[:alpha:]][[:alnum:]]*$"
    p[2] = "^[0-9]+[0-9,]*[.][0-9]{2}$"
}

{
    i = 0
    for (j = 1; j <= NF; ++j) {
        for (k = 0; k in p; ++k) {
            if ($j ~ p[k] && !q[k]++ && j > ++i) {
                $i = $j
            }
        }
    }
    q[0] = q[1] = q[2] = 0
    NF = i
    print
}

输入:

12:23 23:23 ASDFGH 1,232.00 22.00
21:22 12:12 ASDSDS 22.00 21.00 
12:21 11111 11:11 ASADSS 11.00 11.00
22:22 111232 22:22 BASDASD 1111 1,231.00 1,121.00

输出:

12:23 ASDFGH 1,232.00
21:22 ASDSDS 22.00
12:21 ASADSS 11.00
22:22 BASDASD 1,231.00

答案 1 :(得分:1)

Perl-regex风格应解决问题:

(\d\d:\d\d).*?([a-zA-Z]+).*?((?:\d,\d{3}\.\d\d)|(?:\d\d\.\d\d))

它将捕获以下数据(处理您单独提供的每一行):

RESULT$VAR1 = [
          '12:23',
          'ASDFGH',
          '1,232.00'
        ];
RESULT$VAR1 = [
          '21:22',
          'ASDSDS',
          '22.00'
        ];
RESULT$VAR1 = [
          '12:21',
          'ASADSS',
          '11.00'
        ];
RESULT$VAR1 = [
          '22:22',
          'BASDASD',
          '1,231.00'
        ];

示例perl script.pl:

#!/usr/bin/perl
use strict;
use Data::Dumper;

open my $F, '<', shift @ARGV;

my @strings = <$F>;
my $qr = qr/(\d\d:\d\d).*?([a-zA-Z]+).*?((?:\d,\d{3}\.\d\d)|(?:\d\d\.\d\d))/;

foreach my $string (@strings) {
    chomp $string;
    next if not $string;
    my @tab = $string =~ $qr;
    print join(" ", @tab) . "\n";
}

运行方式:

perl script.pl test_data.txt

干杯!