Заменить кратчайшее совпадение строкового рисунка

У меня есть эта строка:

update mytable set mycol=myvalue where mycol=yourvalue; 

Мне нужно преобразовать его в:

 insert into mytemp select * from mytable where mycol=youvalue; 

Я могу сделать это так, и это работает отлично:

 sed -e 's/^Update.*where//ig' -e "s/^/insert into mytemp select * from mytable where /g" n.txt 

НО :

Если строка:

 update mytable set mycol=myvalue where mycol=(select yourcol from yourtable where youcol=yourvalue); 

Я получил:

 insert into mytemp select * from mytable where youcol=yourvalue); 

В то время как я хочу:

 insert into mytemp select * from mytable where mycol=(select yourcol from yourtable where youcol=yourvalue); 

Что я могу сделать?

2 Solutions collect form web for “Заменить кратчайшее совпадение строкового рисунка”

По умолчанию двигатель regex от sed жадный. Это означает, что шаблон всегда соответствует максимально возможному совпадению. Вы должны сделать не жадный поиск, но я думаю, что sed не поддерживает не жадные поиски. Поэтому вы должны добавить опорную точку (ы) к вашему шаблону поиска, чтобы sed нашел кратчайшее возможное совпадение.

Следующая строка пытается подражать нежелательному соответствию для вашего особого случая, и это не требует универсальности, так как один параметр w между update и первый, where делает шаблон недействительным:

 sed -e 's/^Update[^w]*where//ig'\ -e "s/^/insert into mytemp select * from mytable where /g" n.txt 

Другие regex-engine поддерживают эту функцию, например, например, perl и awk .

Но в вашем случае я думаю, что это выражение

 sed -e 's/^Update.\+where\(.\+where.*\)$/\ insert into mytemp select * from mytable where \1/ig' n.txt 

было бы более удобным, связанным с вашей конкретной проблемой.

(трейлинг \ в строках выше добавляется только для того, чтобы сделать строки более разборчивыми.)

Согласование регулярных выражений выполняется слева направо и с самым длинным совпадением. Следовательно, ^Update.*where соответствует последнее вхождение, where на линии.

Один из способов сделать это совпадение – использовать не-жадный квантификатор для * . Сед не поддерживает не жадные кванторы, но perl делает.

 perl -pe 's/^update.*?where//i; s/^/insert into mytemp select .*? from mytable where /' 

Другой способ, который может или не может соответствовать вашим данным, – это отклонить круглые скобки в настройках имени таблицы и столбца.

 sed -e 's/^update[^()]*where//i' -e 's/^/insert into mytemp select [^()]* from mytable where /' 

Более сложный метод заключается в том, чтобы сначала заменить первый, where уникальным маркером, затем сделать свою замену и, наконец, повернуть маркер where . Поскольку sed работает по строкам, строка гарантированно не содержит символ новой строки, представленный \n в sed.

 sed -e 's/ where /\n/' \ -e 's/^update.*$//i' -e 's/^/insert into mytemp select .* from mytable where /' \ -e 's/\n/ where/' 
  • Пустой файл без grep, впоследствии обрабатывающий его как двоичный файл
  • Как извлечь данные из файла и построить имя файла из одного из значений
  • Преобразование таблицы csv в HTML
  • Поиск файла для строки, окруженной двумя другими известными строками?
  • Помощь с повторением поля A в CSV-файле, где поле B имеет указанное значение
  • Grep точное количество цифр и некоторые другие символы
  • Создать в HTML из вывода скрипта bash
  • Обмен одной колонки из файла1 с файлами из файла2
  • Объединение двух частей вместе для создания единого сценария
  • Как печатать текст между первым вступлением пары строк?
  • Как заполнить файл потоком из / dev / urandom с указанным числом строк?
  • Linux и Unix - лучшая ОС в мире.