perl one-liner在同一行中捕获多个匹配

时间:2015-10-09 02:23:47

标签: python perl

我想只从文件中提取数字并组织为CSV。

自:

  Aa:40, Bint:02 :  Bstring = 0x13   Ccc Num = 52   Dfloat = 164.0
  Aa:40, Bint:03 :  Bstring = 0x1B   Ccc Num = 10   Dfloat = 10.6
  Aa:41, Bint:04 :  Bstring = 0x1A   Ccc Num = 10   Dfloat = 1.6

为:

40,02,0x13,52,164.0
40,03,0x1B,10,10.6
41,04,0x1A,10,1.6

我可以用Python re.findall(如下所示)

来做到这一点
for line in sys.stdin:
    print (",".join(re.findall(r'\d+.?\w+', line)))

实现相同的perl方法是什么?

4 个答案:

答案 0 :(得分:4)

您正在从字符串中提取数值。

你可以这样做:

 m/(\d+)/g;

当然,既然您还包括.x

 m/(\d[\d\.xA-F]+)/ig;

或作为一个班轮:

perl -nle 'print join ",",  m/(\d[\d\.xA-F]+)/ig;' 
  • n是&#34;将其换成while ( <> ) {

    这意味着您可以管道STDIN或在其后指定文件 - 例如perl -nle 'print join ",", m/(\d[\d\.xA-F]+)/gi;' somefile cat somefile | perl -nle 'print join ",", m/(\d[\d\.xA-F]+)/gi;'

  • l是自动选择。它chomps换行并在打印后重新添加

  • e执行此代码段。

这有效地使上述一个班轮:

BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    print join(',', /(\d[\d\.xA-F]+)/gi);
}

这给出了;

40,02,0x13,52,164.0
40,03,0x1,10,10.6
41,04,0x1,10,1.6

看起来像您想要的输出。

答案 1 :(得分:3)

foo.pl - python代码段的直接翻译

print join (',', m/(\d+.?\w+)/g), "\n" foreach <STDIN>;

需要注意的重要一点是在寻找匹配时使用/g。这个标志将有效地说我们对字符串中存在的每个匹配感兴趣,而不仅仅是第一个。

当然, one-liner (你特别要求的)可以写成如下,对于未经训练的眼睛来说可能更具可读性:

foreach my $line (<STDIN>) {
  my @data = $line =~ m/(\d+.?\w+)/g);
  print join (',', @data), "\n";
}
% cat data.txt             
Aa:40, Bint:02 :  Bstring = 0x13   Ccc Num = 52   Dfloat = 164.0
Aa:40, Bint:03 :  Bstring = 0x1B   Ccc Num = 10   Dfloat = 10.6
Aa:41, Bint:04 :  Bstring = 0x1A   Ccc Num = 10   Dfloat = 1.6
% cat data.txt| perl foo.pl
40,02,0x13,52,164.0
40,03,0x1B,10,10.6
41,04,0x1A,10,1.6

答案 2 :(得分:1)

尝试这样的事情:

# Declare the regex
my $is_num = qr { 
                    (?: 0x[0-9a-fA-F]+ ) # Match stuff like 0x1B
                    |                    # Or
                    \d+ (?: \.\d+ )?     # 5 or 5.2
                }x; 

chomp(my @data = <DATA>);
for(@data){
   my @new;
   push @new, $1 while /($is_num)/g;
   $_ = join ",", @new;
}

print "$_\n" for @data;

__DATA__
Aa:40, Bint:02 :  Bstring = 0x13   Ccc Num = 52   Dfloat = 164.0
Aa:40, Bint:03 :  Bstring = 0x1B   Ccc Num = 10   Dfloat = 10.6
Aa:41, Bint:04 :  Bstring = 0x1A   Ccc Num = 10   Dfloat = 1.6

输出

40,02,0x13,52,164.0
40,03,0x1,10,10.6
41,04,0x1,10,1.6

我确信有更好的方法可以做到这一点。这是我想到的第一个

答案 3 :(得分:0)

另一种方式

# Declare the regex
my $is_num = qr { 
                    (?: 0x[0-9a-fA-F]+ )  # Match stuff like 0x1B
                    |                     # Or
                    \d+ (?: \.\d+ )?      # 5 or 5.2
                }x;  


chomp(my @data = <DATA>);
for(@data){
   s/.*? ($is_num)/$1,/xg;
   s/\W+$//x;
}
print "$_\n" for @data;

输出相同

40,02,0x13,52,164.0
40,03,0x1B,10,10.6
41,04,0x1A,10,1.6