#regex #sed #replace #multiline
#регулярное выражение #sed #заменить #многострочный
Вопрос:
Я получил код fortran с неприятным старым синтаксисом и хочу перенести на новый синтаксис. Моя sed
команда
sed -nr 'N;s/ns*dDs*//g' file
должен найти нумерованные разрывы строк, но не работает по неизвестной мне причине. Я уже просмотрел здесь множество многострочных sed
вопросов, и я все еще не могу исправить свое недоразумение. Насколько я понимаю, команда работает следующим образом:
N append next line to pattern space; thus pattern space has two lines with n in between
s///g usual search-replace
ns*dDs* matches a newline followed by s*, a digit, a non-digit and a s* again
Исходный код выглядит следующим образом
if(condition) then
call func1(v1, v2, v3, v4
1 ,v5,v6,v7)
else
call func2(v1, v2, v3, v4
1 ,v5,v6,v7)
endif
call MPI_BCAST(num(1),1,MPI_DOUBLE_PRECISION
1 ,masterid,comm,mpinfo)
21 format(' text',2x,f10.5)
и должен преобразоваться в целевой код
if(condition) then
call func1(v1, v2, v3, v4,v5,v6,v7)
else
call func2(v1, v2, v3, v4,v5,v6,v7)
endif
call MPI_BCAST(num(1),1,MPI_DOUBLE_PRECISION,masterid,comm,mpinfo)
21 format(' text',2x,f10.5)
Комментарии:
1. sed не поддерживает
d
илиD
..s
поддерживаетсяGNU sed
(не уверен в других реализациях)… кроме того, использованиеN
(без дополнительных обходных команд) не позволит вам снова использовать эту строку. например, первые две строки сопряжены, поэтому вы никогда не сможете сопоставить 3-ю строку, которая вам нужна
Ответ №1:
Это может сработать для вас (GNU sed):
sed -E ':a;N;s/ns*[0-9]s*([^0-9])/1/;ta;P;D' file
Пройдите по файлу, используя окно из 2 строк.
Если вторая строка начинается с некоторого или без пробелов, за которой следует цифра, за которой следует еще немного или без пробелов, за которой следует не цифра, замените это на не цифру и повторите. В противном случае выведите первую строку окна, затем удалите ее и повторите.
Комментарии:
1. Большое спасибо, это работает для меня! Но я немного смущен комментарием @Sundeep. Если sed с помощью команды
N
считывает файл в совместных строках 12, 34, 56, … вместо 12, 23, 34, … тогда я не понимаю, как приведенная выше команда может соответствовать разрыву строки в 23, 45, … Но, очевидно, это так ?!2. Особенность
D
команды в том, что она не только удаляет до первой новой строки включительно в пространстве шаблонов, но и, если пространство шаблонов не является пустым, подавляет неявное чтение следующей строки и вместо этого переходит к первой команде в цикле sed. Таким образом, если в пространстве шаблонов было 2 строки, вторая становится первой.3. Большое спасибо за подробное объяснение. Кажется, я понял!
Ответ №2:
Вот одно из возможных решений, perl
которое работает для данного образца ввода:
perl -0777 -pe 's/nh*dh*(?=,)//g'
-0777
вывод всего ввода в виде одной строкиnh*dh*
сопоставьте символ новой строки, за которым следуют необязательные горизонтальные пробелы, за которыми следует символ цифры, за которым следуют необязательные горизонтальные пробелы(?=,)
совпадение только в том случае, если после такого совпадения есть символ запятой … в противном случае вам нужно будет указать, как НЕ совпадать21 format(' text',2x,f10.5)
С GNU sed
помощью, но мое понимание этих команд недостаточно хорошо, чтобы быть уверенным:
sed -E 'N; s/ns*[0-9]s*,/,/; P; D'
P Распечатайте часть пространства шаблонов до первой новой строки.
D Если пространство шаблонов не содержит новой строки, запустите обычный новый цикл, как если бы была выдана команда d. В противном случае удалите текст в пространстве шаблонов до первой новой строки и перезапустите цикл с результирующим пространством шаблонов, не читая новую строку ввода.
Комментарии:
1. Ваше
perl
решение работает как шарм! Также вашsed
пример помог мне лучше понять механику, стоящую за этим. Но прежде чем углублятьсяperl
, я стараюсь придерживатьсяsed
, хотя я считаю, что perl намного проще во многих ситуациях.