如何从正则表达式匹配的数字中减去1?

Max*_*lev 7 bash awk regular-expression

我正在尝试编写一个脚本,将行中的每个数字减少“1”,但我得到的是所有“0”:

awk '{a=gensub(/([0-9]+)/,"\\1","g",$0);
     if(a~/[0-9]+/) {gsub(/[0-9]+/,a-1,$0);}
     print $0}'
Run Code Online (Sandbox Code Playgroud)

例如,字符串:

1,2,3,4-7
Run Code Online (Sandbox Code Playgroud)

应该导致:

0,1,2,3-6
Run Code Online (Sandbox Code Playgroud)

相反,我得到:

0,0,0,0-0
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 12

awk替代能力相当有限。gawk具有gensub()可在至少包括在替换匹配的部分的部分,但没有操作可在那些来进行。

可以使用awk,但您需要采取不同的方法:

awk '{
  text = $0
  $0 = ""
  while (match(text, /[0-9]+/)) {
    $0 = $0 substr(text, 1, RSTART-1) \
         (substr(text, RSTART, RLENGTH) - 1)
    text = substr(text, RSTART+RLENGTH)
  }
  $0 = $0 text
  print}'
Run Code Online (Sandbox Code Playgroud)

或者使用 GNUawk作为 @jofel 方法的变体:

gawk -v 'RS=[0-9]+' '{printf "%s", $0 (RT==""?"":RT-1)}'
Run Code Online (Sandbox Code Playgroud)

或者

gawk -v 'RS=[^0-9]+' '{printf "%s",($0==""?"":$0 - 1)RT}'
Run Code Online (Sandbox Code Playgroud)

但是,使用以下方法要容易得多perl

perl -pe 's/\d+/$&-1/ge'
Run Code Online (Sandbox Code Playgroud)

perl可以使用捕获组(as $1, $2... 以及$&整个匹配的部分)并且带有e标志可以perl使用这些来运行任意表达式。


jof*_*fel 7

您的 awk 解决方案仅匹配第一个数字,然后将所有其他数字替换为第一个数字减一。

拿你的程序来说,你可以和 GNU 的 awk ( gawk) 一起使用:

awk 'BEGIN { RS="[^0-9]"; OFS=""; ORS=""; } {a=gensub(/([0-9]+)/,"\\1","g",$0);if(a~/[0-9]+/) {gsub(/[0-9]+/,(a-1),$0);} print $0,RT}'
Run Code Online (Sandbox Code Playgroud)

但这可以简化为

awk 'BEGIN { RS="[^0-9]"; OFS=""; ORS=""; } {if(length($0)) {print ($0-1);}print RT}' 
Run Code Online (Sandbox Code Playgroud)

或者有评论:

awk '
  BEGIN { 
    RS="[^0-9]";  # set the record separator to a regexp matching all 
    OFS="";  # no output field separator
    ORS="";  # no output record separator (we use RT)
 } 
 {
     if(length($0)) { # if number found
       print ($0-1); # print it decreased by one
     }
     print RT # output current field separator (=non-digit). 
 }'
Run Code Online (Sandbox Code Playgroud)

每个非数字都用作记录分隔符,并与打印语句一起重新插入。

这是python中的解决方案:

python -c 'import re,sys; print re.compile("\d+").sub(lambda i: str(int(i.group())-1),sys.stdin.read()),' 
Run Code Online (Sandbox Code Playgroud)