sed - применить подстановку между шаблонами - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть два шаблона START и END, и я хочу заменить каждое пространство подчеркиванием между этими шаблонами.

Пример

Lorem ipsum dolor START sit amet, consectetur END adipiscing elit.

следует преобразовать в

Lorem ipsum dolor START_sit_amet,_consectetur_END adipiscing elit.

Я знаю регулярное выражение для замены каждого пробела подчеркиванием

sed 's/ /_/g'

И я также знаю, как сопоставить часть между двумя шаблонами

sed 's/.*START\(.*\)END.*/\1/g'

Но японятия не имею, как объединить эти две вещи.

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

В качестве альтернативы вы можете использовать Perl:

perl -pe 's/(START.*?END)/$1=~s#\s#_#gr/ge'

Шаблон (START.*?END) соответствует подстроке между START и END при захвате его в группу 1, а затем s#\s#_#gr заменяет каждый отдельный пробел (\s) на _ в содержимом группы.

Или, если вы используете Perl, который не поддерживает опцию r:

perl -pe 's/(?:START|\G(?!^))(?:(?!END).)*?\K\s/_/g'

См. онлайн-демо и второе демо онлайн-регулярных выражений .

(?:START|\G(?!^))(?:(?!END).)*?\K\s соответствует

  • (?:START|\G(?!^)) - START подстрока или конец предыдущего успешного совпадения (с \G(?!^))
  • (?:(?!END).)*? - любой символ, кроме символа разрыва строки, без запуска подстроки END, как можно меньше
  • \K - оператор сброса совпадений, отбрасывающий ранее сопоставленный текст
  • \s - символ пробела.
0 голосов
/ 12 сентября 2018

Использование GNU awk:

awk -v RS='(START|END)' 'RT=="END"{gsub(" ","_")}{printf "%s%s",$0,RT}' file

Это зависит от разделителя записей RS, установленного на START или END.

Если достигнут тег END, запись обновляется, чтобы заменить пробелы подчеркиванием с помощью функции gsub().

Последний оператор печатает всю запись, включая терминатор записи RT (соответствует RS).

Обратите внимание, что это решение позволяет иметь START и END в разных строках (и обязательно в одной и той же строке).

0 голосов
/ 12 сентября 2018

Вы можете использовать это awk для выполнения своей работы:

awk -v ts='START ' -v te='END ' '{
   while (n = index($0, ts)) {
      m = index($0, te)
      if (m > n) {
         s = substr($0, n, m-n)
         gsub(/[[:blank:]]+/, "_", s)
         $0 = substr($0, 1, n-1) s substr($0, m)
      }
   }
} 1' file

Lorem ipsum dolor START_sit_amet,_consectetur_END adipiscing elit.
...