Включение необязательного символа в регулярное выражение с sed - PullRequest
0 голосов
/ 14 апреля 2019

У меня есть следующие строки:

setenv run_area1 root/test1/Apr14_2019_10_32_39/dummy
setenv area2 root/test2/Aug23_2017_14_25_56/dummy
setenv run_area3 testRun/test1/blue_Apr14_2019_08_56_48/dummy/
setenv area4 testRun/test2/Aug23_2017_14_26_03/thing2

Я хочу заменить дату на [DATE] следующим образом:

setenv run_area1 root/test1/[DATE]/dummy
setenv area2 root/test2/[DATE]/dummy
setenv run_area3 testRun/test1/blue[DATE]/dummy/
setenv area4 testRun/test2/[DATE]/thing2

Мне нужно использовать sed, поэтому я написал следующую команду:

sed 's|[A-Z][a-z]*[0-9]*_[0-9]*_[0-9]*_[0-9]*_[0-9]*|[DATE]|g'

Хорошо работает для строк, но для следующего:

setenv run_area3 testRun/test1/blue_Apr14_2019_08_56_48/dummy/

Я получаю:

setenv run_area3 testRun/test1/blue_[DATE]/dummy/

Я ищу способ использования _ в регулярном выражении. В Perl я знаю, что могу использовать что-то вроде (_|), поэтому _ необязательно. Также я мог бы использовать ?. В предыдущих темах я видел, что базовый sed не включает эти опции, и мне нужно использовать \{0,1\}. ( ссылка ). Проблема в том, что я не могу понять, как \{0,1\} решает это. Есть ли другие решения?

Ответы [ 3 ]

1 голос
/ 14 апреля 2019

\{0,1\} в BRE - это интервал регулярного выражения, который означает 0 to 1 repetitions of the preceding expression, что совпадает со значением ? в ERE (технически в ERE оно определяется как 0 _or_ 1, но это тот же набор значений!) то есть, что предыдущее выражение не является обязательным.

С любым POSIX sed:

$ sed 's/_\{0,1\}[[:upper:]][[:lower:]]*[0-9]*\(_[0-9]*\)\{4\}/[DATE]/' file
setenv run_area1 root/test1/[DATE]/dummy
setenv area2 root/test2/[DATE]/dummy
setenv run_area3 testRun/test1/blue[DATE]/dummy/
setenv area4 testRun/test2/[DATE]/thing2
0 голосов
/ 14 апреля 2019

Если месяц и данные соответствуют формату MMMDD, вы можете считать такое выражение уникальным в записи и основывать свой сценарий на этом предположении. Примерно так:

sed -E 's/^(.*)([[:alpha:]]{3}[[:digit:]]{2})([^/]+)\/(.*)$/\1[DATE]\/\4/;s/_\[DATE\]/[DATE]/' filename

выход

setenv run_area1 root/test1/[DATE]/dummy
setenv area2 root/test2/[DATE]/dummy
setenv run_area3 testRun/test1/blue[DATE]/dummy/
setenv area4 testRun/test2/[DATE]/thing2

Примечание: Опция -E с sed включает расширенное регулярное выражение, которое, если не поддерживается, использует опцию -r.

0 голосов
/ 14 апреля 2019

Поскольку sed использует basic regular expression по по умолчанию . Чтобы узнать разницу между basic regular expression и extended regular expression, перейдите по этой ссылке .

Если вы хотите использовать функции, поддерживаемые extended regular expression. Вы должны явно указать sed с опцией -r.

Так что с GNU sed приведенные ниже скрипты фактически делают то же самое.

sed 's|_\?[A-Z][a-z]*[0-9]*_[0-9]*_[0-9]*_[0-9]*_[0-9]*|[DATE]|g' textfile

sed -r 's|_?[A-Z][a-z]*[0-9]*_[0-9]*_[0-9]*_[0-9]*_[0-9]*|[DATE]|g' textfile
...