Intereting Posts
Ошибка ввода / вывода, не может установить ничего Установите минус двух списков с завершающим символом новой строки / общий черный список с использованием общих предметов домашнего обихода Потрясающее поведение округления с печатью В чем разница между темами ZSH, приглашениями и темами на основе терминала? Не удается открыть Natron на Ubuntu? Почему каждая переменная не инициализируется значением своего значения по умолчанию для объявления в Bash? rsync -vvv застрял в OS X без четкого объяснения Вставить текст по определенному номеру строки Не удалось загрузить диск под Linux Как остановить людей, нарушающих dataset ZFS, который используется только для получения? Как я могу использовать sed или ex для замены блока (многострочный код) новым блоком текста (кода)? Как завершается работа Bash с помощью sudo? Почему мой компилятор vim-7.3 не включает сервер клиентов? Заполнение rsyslog / var / log ставит систему вниз Сохранение истории bash из нескольких Konsole не работает правильно

Как вычесть 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 

Возможности замены 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}' 

Или с GNU awk как вариацией подхода @ jofel:

 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 с ними.

Ваше решение awk соответствует только первому числу, а затем заменяет все остальные номера первым сокращенным на единицу числом.

Принимая вашу программу, вы можете использовать ее с awk ( gawk ) GNU:

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

Каждая нецифровая цифра используется как разделитель записей и повторно вставлена ​​в оператор печати.

Здесь решение в python:

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

Использование универсального (не-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