Кто пришёл в редактор vim, уже зная регулярные выражения по другим языкам, обычно испытывает лёгкий шок. Привычная группировка в круглых скобках вдруг требует обратной косой черты перед каждой скобкой. Квантификатор повторения - тоже. Логическое ИЛИ - тоже. Выражение, которое в python или perl читалось чисто, в редакторе обрастает частоколом бэкслешей и становится почти нечитаемым. Причина в том, что синтаксис регулярных выражений vim ближе к старому стандарту, чем к перловому, и многие метасимволы по умолчанию надо экранировать.
У редактора есть лекарство - режимы магии, переключающие, какие символы считать особыми, а какие буквальными. Самый удобный для тех, кто знает перловые выражения, - очень магический режим, включаемый префиксом из обратной косой и буквы v. Он делает особыми почти все символы, избавляя от экранирования групп и квантификаторов. Разберём, как он работает, какова его обратная сторона, и почему в скриптах режим магии стоит задавать явно всегда.
Очень магический режим делает особыми почти все символы
Префикс из обратной косой черты и строчной буквы v, поставленный в начало шаблона, включает очень магический режим. После него особое значение получают все символы, кроме цифр, латинских букв и знака подчёркивания. Группировка, квантификаторы, чередование начинают работать без всякого экранирования, как в перловых выражениях.
Сравним поиск строк, содержащих одно из двух слов с двоеточием. В обычном режиме скобки и вертикальная черта требуют бэкслешей.
/\(error\|warning\): обычный режим: частокол бэкслешей
/\v(error|warning): очень магический: чисто и читаемо
Разница очевидна. Во втором варианте группировка и чередование пишутся прямо, без обратных косых, и выражение читается так же, как читалось бы в знакомом языке. Чем сложнее шаблон, тем заметнее выигрыш.
/\v[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
Этот шаблон для длинного шестнадцатеричного идентификатора в очень магическом режиме читается без единого лишнего бэкслеша - фигурные скобки счётчика повторений работают напрямую. В обычном режиме каждая фигурная скобка потребовала бы экранирования, и выражение превратилось бы в кашу.
Замена через :s выигрывает от очень магического режима не меньше поиска
Префикс работает не только в поиске, но и в команде замены, где читаемость особенно важна, потому что выражения там обычно длиннее. Классический пример - перестановка двух слов местами с захватом групп.
:s/\(cat\) hunting \(mice\)/\2 hunting \1/
:s/\v(cat) hunting (mice)/\2 hunting \1/
Второй вариант, в очень магическом режиме, обходится без бэкслешей вокруг групп. Захваченные группы по-прежнему подставляются в замену через обратную косую с номером - это синтаксис подстановки, а не группировки, и он остаётся прежним.
Реальная польза раскрывается на форматировании текста. Допустим, нужно превратить список слов в пары значений в скобках с разным регистром. В обычном режиме скобки, запятые и кавычки придётся экранировать, и выражение станет нечитаемым нагромождением. В очень магическом режиме оно собирается куда чище.
:%s/\v(\w+)/("\U\0\L", "\u\0"),/
Здесь группа слова берётся без экранирования, а управляющие последовательности смены регистра - перевод в верхний, в нижний, заглавная первая буква - подставляют захваченное в нужном виде. Без очень магического режима то же выражение пестрело бы обратными косыми перед каждой скобкой и запятой.
Обратная сторона режима требует экранировать буквальные символы
Тут притаился подводный камень, и он логически вытекает из самого принципа режима. Раз почти все символы стали особыми, то для поиска их буквального значения теперь нужно экранирование - ровно наоборот по сравнению с обычным режимом. Если в очень магическом режиме нужно найти буквальную круглую скобку, её придётся экранировать, иначе она будет воспринята как открытие группы.
/\v\(foo\) ищем буквальные скобки вокруг foo
/\v(foo) а это уже группа, скобки не буквальны
Это переворот привычной логики. В обычном режиме буквальная скобка пишется как есть, а группа требует бэкслеша. В очень магическом всё зеркально: группа пишется чисто, а буквальная скобка требует бэкслеша. Тот, кто переключился на режим, но по инерции пишет буквальные спецсимволы без экранирования, получит совсем не то совпадение, что ждал.
Запомнить правило просто: в очень магическом режиме экранируются именно те символы, которые должны остаться буквальными. Цифры, буквы и подчёркивание буквальны всегда и в экранировании не нуждаются - всё остальное при буквальном использовании просит обратную косую.
Четыре уровня магии и зачем их знать
Очень магический режим - не единственный. У редактора их четыре, и стоит знать всю шкалу, чтобы выбирать осознанно. Очень магический включается буквой v и делает особыми почти все символы. Магический режим, обозначаемый буквой m, - это поведение по умолчанию: часть метасимволов вроде точки и звёздочки особые сразу, а группы и квантификаторы требуют экранирования. Именно в нём редактор работает, пока режим не сменён.
Два противоположных режима делают символы буквальными. Немагический, обозначаемый заглавной M, оставляет особыми лишь немногие символы. А очень немагический, заглавная V, делает буквальными почти все символы, и чтобы вернуть символу особое значение, его надо экранировать. Этот последний бесценен для поиска строк, насыщенных спецсимволами, - например, путей к файлам, где косые черты и точки нужно искать буквально.
/\Vextension\.tar\.gz очень немагический: точки буквальны без хлопот
Полезный мнемонический приём: если забыл, какие символы в редакторе особые, начни шаблон с буквы v или V, чтобы разом включить или выключить особое значение у всех. Очень магический режим включает всё, очень немагический выключает всё, и думать о каждом символе по отдельности больше не нужно.
В скриптах режим магии задают явно во избежание сюрпризов
Есть важная оговорка для тех, кто пишет выражения не для разовой правки, а в конфигурации редактора или в плагинах. Поведение метасимволов по умолчанию зависит от пользовательской настройки магии, которую теоретически можно изменить. Выражение, написанное в расчёте на стандартный режим, поведёт себя иначе, если пользователь сменил настройку.
Поэтому выражения в скриптах должны всегда явно задавать один из режимов через соответствующий префикс. Это делает их невосприимчивыми к настройкам пользователя - выражение ведёт себя одинаково независимо от того, что выставлено в окружении. Менять глобальную настройку магии в конфигурации, к слову, настоятельно не советуют: это с большой вероятностью сломает установленные плагины, чьи авторы рассчитывали на стандартное поведение.
Для удобства повседневного поиска многие назначают сочетание, которое сразу начинает поиск в очень магическом режиме, чтобы не набирать префикс вручную каждый раз. Это переназначение клавиши поиска так, чтобы она автоматически добавляла префикс режима.
:nnoremap / /\v поиск всегда стартует в очень магическом режиме
Что складывается в практику
Картина выстраивается ясно. Очень магический режим через префикс из обратной косой и буквы v - выбор для тех, кто знает перловые или расширенные регулярные выражения и хочет писать их в редакторе без частокола бэкслешей. Группы, квантификаторы, чередование работают напрямую, выражения становятся читаемыми, а на сложных шаблонах выигрыш огромен. Работает он одинаково и в поиске, и в команде замены.
Обратная сторона - зеркальная логика экранирования: то, что должно остаться буквальным, теперь требует обратной косой. Привычку писать буквальные спецсимволы без экранирования придётся пересмотреть. На другом полюсе шкалы стоит очень немагический режим, незаменимый для поиска строк со множеством спецсимволов вроде путей к файлам.
Главная мысль: режим магии - это рубильник, решающий, кто особый, а кто буквальный. Знание всей шкалы из четырёх уровней позволяет под каждую задачу выбрать удобную сторону: очень магический для сложных шаблонов с группами, очень немагический для буквального текста. А в скриптах режим задают явно всегда, чтобы выражение не зависело от чужих настроек. Стоит освоить эту шкалу, и регулярные выражения редактора из источника раздражения превращаются в инструмент не хуже знакомых по другим языкам.