正規表現に一致する数を1つ減らすには?

正規表現に一致する数を1つ減らすには?

連続した各数字を「1」ずつ減らすスクリプトを作成しようとするのに得たのは「0」だけです。

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

たとえば、文字列は次のようになります。

1,2,3,4-7

結果は次のとおりです。

0,1,2,3-6

代わりに、私は次のようになります。

0,0,0,0-0

答え1

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}'

あるいは、awk@jofelのメソッドの変形としてGNUを使用してください。

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

または

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

しかし、ここで使用する方が簡単ですperl

perl -pe 's/\d+/$&-1/ge'

perlキャプチャグループ(たとえば$1$2...、および$&完全一致部分)を使用でき、このeフラグを使用してこれらのキャプチャグループを使用して任意の式を実行できますperl

答え2

あなたのawkソリューションは最初の数字だけを一致させ、他のすべての数字を最初の数字から1を引いた数字に置き換えます。

プログラムの場合は、gawkGNUのawk()で使用できます。

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}'

ただし、これは次のように単純化できます。

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

またはコメントを追加してください。

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). 
 }'

数値以外の各々はレコード区切り文字として使用され、print文とともに再挿入されます。

Pythonソリューションは次のとおりです。

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

答え3

汎用(GNUではない)「awk」を使用してください。

入力行を値と区切り文字の配列に分割することをお勧めします。その後、値を変更して区切り文字に再グループ化します。

awk '{
    split("0," $0 ",0", numbers, "[^0-9]+"); # make sure each line starts and ends with a number
    split($0, sep, "[0-9]+");
    res = ""; j = 1;
    for (i = 2; i < length(numbers); i ++) { # ignore the dummy numbers added above
        res = res sep[j++] (numbers[i] - 1);
    }
    print res;
}' file

関連情報