подстановка регулярного выражения perl группами - PullRequest
0 голосов
/ 10 мая 2018

У меня есть следующий вход JSON

... "somefield":"somevalue", "time":"timevalue", "anotherfield":"value" ...

внутри моего скрипта ksh я хочу заменить значение времени своим значением. Так что я создал это регулярное выражение, используя группы с работами просто отлично

data=`cat somefile.json`
echo $data | perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\1%TIME%\2|g" | another-script.sh

... "somefield":"somevalue", "time":"%TIME%", "anotherfield":"value" ...

Однако ... я не могу использовать число в качестве замены, потому что perl использует числа для определения групп ... так что этот, очевидно, не работает

perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\120:00:00\2|g"

Я могу преодолеть это путем двухшаговой подстановки

perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\1%TIME%\2|g" | perl -pe "s|%TIME%|20:00:00|"

... "somefield":"somevalue", "time":"20:00:00", "anotherfield":"value" ...

но я уверен, что есть лучший и более элегантный способ сделать это

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Perl не использует \1 для подстановки. Если бы вы включили предупреждения (например, с perl -w), Perl сказал бы, что это $1. Который можно убрать из окружающих цифр, добавив { }:

perl -pe 's|(.*time"\s*:\s*").*?(".*)|${1}20:00:00$2|g'

(Я также удалил все избыточные обратные слэши из регулярного выражения.)

С другой стороны, какой смысл сопоставлять .*, если вы просто собираетесь заменить его самостоятельно? Разве это не может быть

perl -pe 's|(time"\s*:\s*").*?(")|${1}20:00:00$2|g'

Я не большой поклонник .* или .*?. Если вы пытаетесь сопоставить внутреннюю часть строки в кавычках, было бы лучше указать:

perl -pe 's|(time"\s*:\s*")[^"]*(")|${1}20:00:00$2|g'

Мы не пытаемся проверить входную строку, так что теперь действительно нет причин совпадать с этим окончательным " (и заменить его самостоятельно):

perl -pe 's|(time"\s*:\s*")[^"]*|${1}20:00:00|g'

Если ваш perl не древний (5.10+), вы можете использовать \K, чтобы «сохранить» ведущие части строки, то есть не включить его в матч:

perl -pe 's|time"\s*:\s*"\K[^"]*|20:00:00|g'

Теперь будет заменена только часть [^"]*, что избавит нас от необходимости делать захват.

0 голосов
/ 10 мая 2018

Хотя вы могли бы делать это с помощью регулярных выражений, было бы намного проще с подходящим инструментом

jq '.time="20:00:00"' somefile.json 

Если вы особенно хотите использовать Perl, основной дистрибутив Perl включает JSON-анализатор с 2011 года, так что вы можете сделать что-то вроде:

perl -MJSON::PP=decode_json,encode_json -0 -E '$j = decode_json(<>); $j->{time} = "20:00:00"; say encode_json($j)' somefile.json
...