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

Рубрика "Секреты Вим". Магия регэкспов и регистр символов

Привет, коллеги. Поговорим о магии, регулярных выражениях и учете/игнорировании регистра символов.

Как мы все знаем, в регулярном выражении есть символы, означающие сами себя, и есть спецсимволы, смысл которых иной. Слеш (\) превращает обычный символ в специальный и наоборот. Так, n означает букву n, но \n — это символ конца строки, тогда как \\ — это сам слеш.

Классикой регулярных выражений является использование точки как "любой символ", квадратных скобок для класса символов ([a-z] или [аоуеэи]), символов ^ и $ как якорей начала и конца строки, * как мультипликатора "нуль или более вхождений".

Это всё называется магией, вполне официально.

Но вы можете сами решать, сколько магии вам надо.

Дело в том, что есть развилка. В текстовом редакторе иногда не надо много магии: лучше, чтобы почти все символы означали сами себя, и можно было найти многоточие как /... А иногда нужно нормальное регулярное выражение, чтобы найти ^\s*[a-z]\+. А порой лучше, чтобы вообще всё, кроме букв и цифр, имело особый смысл. Например, чтобы + означал "один или более", как в Перле, а не знак "плюс".

Когда символ означает сам себя, говорят, что он трактуется литерально.

Можно указать в регулярном выражении (в любом месте) один из символов \v, \m, \M, \V. Первый, расшифровываемый как "very magic", трактует только буквы, цифры и знак _ литерально: всё остальное волшебно. Его антипод \V трактует всё литерально, кроме слеша и символа, который заканчивает регулярное выражение (/ или ?).

То есть, в обоих случаях вам всё доступно, только вопрос в удобстве: удобнее искать /\V...***...***[[[]]]/, но /\v(^\s*[a-z]+$)|(^\s+$)/

Если вы ищете просто текст, возможно, длинный, или, скажем, формулы, то \V незаменимо. А для сложных длинных выражений полезно \v.

Варианты \m и \M компромиссны. Первое соответствует обычным регулярным выражениям Вим и включено, если выставлен флаг magic (по умолчанию). Второе чуть менее волшебно и соответствует сброшенному флагу (nomagic). Сами эти последовательности позволяют флаг обойти. В режиме nomagic литеральна точка, звездочка, тильда; но волшебны крышечка и доллар. Квадратные скобки литеральны, а для класса символов достаточно экранировать только первую: \[a-z]. В режиме magic всё перечисленное волшебно, но вот +, |, круглые и фигурные скобки литеральны.

Основная разница: в режиме magic выражение ^.*$ означает "что угодно, строка целиком", а в режиме nomagic это "точка и звездочка и больше ничего на строке". В режиме \V это просто данный текст: "^.*$".

Итак, вы можете:

  1. Работать в парадигме Вим (при включенной magic). Это довольно разумный компромисс, но надо привыкнуть, что \w\+, а не \w+.
  2. Выставить nomagic и работать почти просто с текстом (только \, ^, $ означают не себя).
  3. Настраивать каждое выражение отдельно, задавая последовательность \v, \m, \M, \V.

Пример: "Строка состоит из двух одинаковых частей" выглядит так:

  • /\v^(.+)\1$
  • /\m^\(.\+\)\1$/ и это так без \m, если выставлена magic (по умолчанию).
  • /\M^\(\.\+\)\1$/ и это так без \M, если выставлена nomagic.
  • /\V\^\(\.\+\)\1\$/

Круглые скобки, волшебные или со слешем, захватывают текст. А символ \1 означает "то, что захватили первые по счету скобки".

Команды замены есть с заданной магией. Но о них будет отдельный материал.

Теперь про регистр символов. Рекомендую мой материал про регистр вообще и как его менять в Вим. А сегодня поговорим про его учет при поиске.

Поиск по регулярному выражению может учитывать регистр, а может игнорировать. Иногда нужно одно, иногда необходимо другое. Есть опция-флаг ignorecase: если включена, то поиск регистронезависим, и поиск любого слова из Francesca, francesca, FRANCESCA найдет любое из них. Если вы работаете на Фортране, включайте; если на С++, то отключайте. Если с текстом — смотрите по ситуации.

Есть еще smartcase, тоже флаг. Учитывается только при выставленном ignorecase, что логично. Если шаблон не содержит заглавных букв, то регистр игнорируется: francesca совпадет с любым из вариантов выше. А вот если заглавные буквы есть, то регистр учитывается, так что Francesca совпадет только с Francesca. Этот трюк не работает с *, # , gd и т.п.: только с /, ?, n, N, фильтрами :g, :v, заменой :s. Если вы ищете слово, то либо регистр учитывается, либо нет.

Можно в конкретном выражении включить или отключить учет регистра: для этого есть ключи \c и \C. Первое предписывает игнорировать регистр, второе предписывает учитывать, независимо от флагов, описанных выше.

Ещё есть ключ \Z, который предписывает игнорировать символы-модификаторы Юникода. Для русского языка это не очень важно, у нас с диакритикой только ё, Ё, й, Й (да и для них обычно используем цельные символы), а вот для языков с диакритикой это может быть полезно. А если вы работаете с огласованным ивритом или арабским, то это точно очень полезно!

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

До встречи, коллеги!

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