Найти тему
Блокнот математика

Рубрика "Секреты Вим". Команда замены

Привет, коллеги. Познакомимся поближе с командой замены :s.

Которая есть не только в Вим или, скажем, в Перл: она есть много где, от sed до Скайпа, в котором можно (или можно было) исправить посланное сообщение этой командой. Но везде свои нюансы.

Общеизвестно, что она имеет вид :s/выражение/замена/, ищет на текущей строке первое совпадение с указанным регулярным выражением и заменяет его на строку замены. Можно указать в начале диапазон строк (как вариант, % для всего текста) и/или ключ g после закрывающей черты, чтобы заменить все вхождения на каждой обрабатываемой строке, а не только первое на каждой строке.

Читайте меня и такая книга вам не понадобится!
Читайте меня и такая книга вам не понадобится!

Менее известно, что можно указать еще и число строк после команды:
:s/Francesca/Paola/11

При этом замена происходит в текущей строке и ниже, в указанном числе строк. Если дан диапазон, то начиная от последней строки диапазона. Но не в нем самом!

Кроме наклонной черты /, можно использовать другой ограничитель (но один и тот же в пределах одной команды, конечно). Это должен быть однобайтовый символ (sъъъ нельзя, к сожалению), не алфавитно-цифровой (ssss тоже не годится), и не \, ", |. Остальное можно, при этом саму черту, разжалованную из ограничителей, можно свободно использовать. А новый ограничитель нельзя, разве что экранировать его слешем. Вот как можно:

:s;/;//; — разделитель "точка с запятой"
s.6.7., — разделитель "точка"
s@Francesca@Paola@ — разделитель @

Можно именовать команду и полным именем: substitute.

Ключей, кроме g, есть еще несколько. Так, c запрашивает подтверждение каждой замены. Дается подсказка, как отвечать, но вот полный список ответов: y для "да" (yes), l для "да и заканчивай" (last), n для "нет" (no), a для "да для всех" (all), q или <ESC> для завершения вообще. Еще можно пролистать экран, чтобы осмотреться: <C-E> и <C-Y> для вверх и вниз, соответственно.

Ключ e подавляет сообщение об ошибке, если совпадение не нашлось. Это очень важно для привязок, пакетной обработки и скриптов. А иначе процесс прервется по ошибке в случае, если просто ничего менять не пришлось. Например, вы хотите заменить во всех файлах переменную qq на working_frequency. Если ее в файле нет, это же не проблема.

Ключи i и I отключают/включают учет регистра в регулярном выражении и это еще один способ помимо опций ignorecase и smartcase и ключей самого регулярного выражения \c и \C. Причем ключи регэкспа "сильнее" и в случае конфликта доминируют они.

Ключ n подавляет замену, так что выражение замены роли не играет, а ключ c игнорируется. Просто подсчет числа совпадений. Часто совмещается с g. И это удобно, если вам надо посчитать число слов, например, или еще чего-нибудь.

Ключи p, # и l выводят строки, в которых нашлось совпадение. Замену делают. Это бывает удобно, если совпадений не слишком много. Решетка всегда печатает и номер строки, p только если номера включены (флаг number).

Ключ & должен идти первым и он означает "те же ключи, что и в прошлый раз". Особенно полезен при повторах замены.

Ключ r предписывает использовать при повторе последнее использованное выражение. Использованное как при поиске, так и при замене. Этот ключ уместен только для повторов, о которых чуть далее.

Давайте сначала обсудим умолчания. Можно опустить регулярное выражение и тогда будет использовано выражение последней операции замены. А если его нет, то выражение последней операции поиска. Так, :s//666/ заменит на 666 то, что вы заменяли в прошлый раз.

Если опущено выражение замены, то найденный текст заменяется на "ничто", то есть удаляется. Это может иметь вид :s/42// или даже :s/42

Последнее, впрочем, без флагов. Даже команда :s/ возможна: она удалит первое вхождение на данной строке того, что вы заменяли в прошлый раз.

А вот команда :s работает иначе! Это повтор предыдущей команды замены. Обсудим же повторы замены.

Очень часто надо именно что повторить замену. Для этого есть много "синтаксического сахара", помимо просто опускания выражения (как в s//new/).

Можно просто опустить всё, дав команду :s. Это повтор предыдущей замены: то же выражение поиска, та же строка замены. Но без ключей! Ключи не сохраняются.

Это важно, потому что команда :s/6/60/g на строке 666 превратит ее в 606060, а вот попытка повторить то же на другой такой строке даст 6066. Казалось бы, повторим еще раз; но нет. Еще один повтор приведет уже к нежелательному 60066.

Но ключи можно и указать, превратив команду в :sg, например. Можно и пробел поставить во избежание проблем и недопонимания. Возможность клеить ключи к команде по сути создает кучу команд повтора, таких как :sc, :sIg, :sgi. Но на всякий случай, команды scr, se, sig, sil, sn, sp, sl, sre имеют иной смысл!

Кроме :s, есть и :&. Это синоним. Она имеет то преимущество, что после нее можно поставить ключ & ("те же ключи, что и в прошлый раз"), тогда как после :s это не годится: символ будет понят как разделитель, так что :s& сделает совсем не то, что вы хотели! А вот :&& сделает именно то: повтор прошлой замены с теми же ключами.

Еще есть вариант :~, к которому можно добавить флаги и число строк. Это равносильно :&r, то есть будет использовать последнее выражение для поиска и последнее выражение замены.

Есть команды нормального режима: & повторяет замену (без флагов), g& делает то же, используя выражение для поиска.

Почему так много внимания уделено выражению для поиска? Потому что часто мы ищем что-то, потом заменяем. И вот здесь уместно заменить то, что только что нашли.

Мы уже обсуждали магию регулярных выражений: сколько символов имеют особое значение. Магичность можно менять, я уже рассказывал, для замены это всё тоже работает. Кому-то важнее возможности регулярок, кому-то лучше поменьше слешей. Особых ключей в команде замены для этого нет, потому что чтобы добраться до ключей, надо разобраться, где искомое выражение, а где строка замены. А для этого надо знать, какой символ что означает.

Однако есть специальные команды для любителей: :smagic и :snomagic. Конечно, они нужны для привязок и скриптов.

Теперь обсудим особые символы (магию) в выражении замены.

Прежде всего, если оно начинается с \=, то всё выражение трактуется именно как выражение, и вычисляется, и подставляется результат. Это как ключ e в регулярных выражениях Перл. В этом выражении не должно быть символа-ограничителя (а в результате он может быть). Совпадение доступно как submatch(0). Если были захваты, они доступны тоже по номерам: submatch(1) и т.п.

Примеры из Справки:

:s@\n@\="\r" . expand("$HOME") . "\r"@

Здесь нестандартный ограничитель.

s/E/\="\<Char-0x20ac>"/g

Заменяет E на знак €.

:s!\([0-9+*/.-]\+\)\s*=!\=submatch(0).string(eval(submatch(1)))!g

Вычислит в тексте простые арифметические выражения вида 4+5= и подставит значение после знака равенства.

Теперь просто особые символы. Символ & (в режиме nomagic это \&) означает "всё совпадение". То же означает и \0. Так можно поставить что хотите в скобки: :s/\d\+/(&)/

Символы \1 - \9 означают захваченное скобками. Они могут применяться в самом регулярном выражении, но и в выражении замены тоже. Внимание: в Перл не так! Вот пример:

:s/\(\w\.\w\.\)\s\+\(\w\+\)/\2, \1/g

эта команда заменит на строке все структуры вида "H.J. Potter" на "Potter, H.J.". Правда, только по-английски, потому что \w совпадает с латиницей, а с кириллицей нет. Это решаемо, но не о том сейчас речь.

Символ ~ (без магии \~) означает "та же строка замены, что и в прошлый раз". Это же значение имеет простой символ %, но только если в опции cpoptions есть флаг / (а по умолчанию его там нет).

Символы \u, \U, \l, \L, \e, \E позволяют менять регистр символов. Так, \u& позволяет сделать первую букву совпадения заглавной, а \U& сделает весь совпавший текст КАПСЛОКОМ. Действие \U и \L можно ограничить, поставив \E или \e (это синонимы). Связочка \L\u позволяет "исправить" регистр, озаглавив слово. То есть, frANcESCa станет Francesca. Символ \L переводит всё в нижний регистр, но \u делает первую букву заглавной, отдавая остальное \L.

Вот так можно озаглавить каждое слово в названии статьи, например:

:s/\<\w*\>/\u\L&/g

Символы \t и \\ вставляют табуляцию и сам слеш.

В следующий раз обсудим немного практику замены.

Удачи, коллеги!

Научно-популярные каналы на Дзене: путеводитель
Новости популярной науки12 марта 2022

Наука
7 млн интересуются