정규식과 일치하는 숫자를 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

관련 정보