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

Рубрика "Секреты Вим". Тонкости поиска

Привет, коллеги. Обсудим поиск поподробнее. Основы я уже излагал, а теперь пришло время для более пристального разбора.

Я научу вас находить в тексте и слова, и что угодно.
Я научу вас находить в тексте и слова, и что угодно.

Для поиска есть команды / и ?, включающие особую командную строку, в которой можно ввести искомый текст. Текст этот трактуется как регулярное выражение. Есть возможности для настройки: от "все символы, кроме \, означают себя" до "все символы, кроме алфавитно-цифровых, имеют особое значение". Об этой магии мы уже беседовали, и там же об учете/игнорировании регистра тоже.

Сама командная строка обладает некоторыми особыми возможностями. Есть история, для поиска своя, отделенная от истории команд. Можно переключать раскладку, так же, как в буфере (<C-^>). Можно вставить регистр посредством <C-R>. Это же сочетание позволяет вставить слово под курсором, что бывает очень удобно: <C-R><C-W>. А вот отдельно <C-W> удаляет слово слева от курсора. <C-U> удалит все от начала строки до курсора. Вы можете определять привязки для командной строки через cmap. Есть и другие возможности и спецклавиши, на которых останавливаться не будем. Разве что упомяну еще хитрое сочетание <C-\>e, после которого надо ввести выражение и оно будет вычислено, и его результат станет выражением поиска. Так можно искать, например, результат арифметического действия, которое лень делать в уме: <C-\>e360-66.6<CR>

Итак, команда /текст/. Второй слеш необязателен, в конце надо ввод нажать, конечно. После второго слеша можно дать смещение.

Смещение позволяет сместить курсор относительно найденной позиции, которая обычно — первый символ найденного. Можно сместиться на указанное число строк вниз, указав число n или +n. Можно сместиться вверх, указав -n. Например, /end\s*subroutine/-1 — найти конец функции и сместиться на строку выше.

Просто + и - тоже работают — по умолчанию n=1.

Можно смещаться горизонтально на n символов от начала: s+n или s-n, можно s заменить на b.

Можно попасть в конец совпадения (e) или на n символов влево или вправо: e+n или e-n. Например,

  • /Francesca/s+2 — курсор окажется на первой a,
  • /Francesca/b+2 — то же,
  • /Francesca/e — курсор окажется на последней a,
  • /Francesca/e-2 — курсор на s,
  • /Francesca/e+1 — курсор на символе после последней a.

Это удобно для операторов, например: d/Francesca/e — удалить текст от курсора до имени, включая и само имя.

Особое смещение — это точка с запятой. После нее надо указать новый поиск. Например, /function/;/end\s*function/

Можно указать повторитель перед поиском: 3/Francesca/ — это означает "искать третье вхождение".

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

Можно дать новое смещение после второго слеша: //. Или не давать, и тогда смещения не будет. То есть, /<CR> ищет то же с тем же смещением, а //<CR> ищет то же без смещения.

Команда ? вместо / делает всё то же самое, только поиск идет в обратном направлении: вверх по тексту.

Повторить поиск можно командами n и N — первая ищет в том же направлении, вторая в обратном.

А команды gn и gN сазу выделяют найденное, только они не учитывают смещение.

Обсудим подробнее "прошлый поиск". Искомое выражение сохраняется, причем отдельно для поиска и для команды замены :s. Если для поиска ничего не сохранено, используется сохраненное выражение для замены, если оно есть. Магичность (опция magic) выражения сохраняется, а вот учет регистра (ignorecase) — нет. Так что если вы искали francesca при включенном ignorecase, а потом выключили, то повторный поиск может ничего и не найти.

Искомое выражение доступно в регистре / и его можно вставить в текст ("/p) или использовать в выражении. В частности, задать: :let @/ = 'Francesca'. Есть одна тонкость: задание пустой строки сбрасывает выражение совсем, как будто оно не задано. Что логично, поскольку пустая строка совпадает везде.

Повторный поиск идет после конца найденного совпадения. Так, /66 совпадет с первыми двумя цифрами в 666, повторный поиск не совпадет вообще, если больше шестерок в тексте нет. Однако это если в опции cpoptions есть флаг c (а по умолчанию он там есть). Если нет (а убрать его оттуда лучше с помощью :set cpoptions-=c), то новое совпадение ищется на один символ правее начала текущего совпадения и повторный поиск 66 совпадет на второй и третьей шестерке.

Вообще, эта опция содержит флаги совместимости с vi и позволяет менять поведение в самых разных областях. Вот флаг c относится к поиску.

Давайте вернемся к направлению поиска. Команда / ищет вниз, команда ? ищет вверх, команды n и N повторяют поиск в том же направлении, что и предыдущий, и в противоположном. А вот поведение при достижении края текста — зависит от опции-флага wrapscan. Если она выставлена (так по умолчанию), то поиск зациклен: при достижении конца текста поиск возобновляется с начала, и наоборот. При этом выводится сообщение типа "достигнут конец текста, продолжаем с начала". Сообщение можно отключить, см. опцию shortmess. Если же найти текст не удалось, выводится сообщение об ошибке "Шаблон не найден".

При сброшенном флаге поведение иное: поиск останавливается в конце или начале текста, а если найти искомое не удалось, то сообщение другое: "Достигут конец текста, шаблон не найден".

Чтобы ограничить поиск диапазоном строк, можно использовать в регулярном выражении спецсимволы \%>42l и \%<42l, где вместо 42 стоит номер. Они означают "от строки" и "до строки". Есть еще \%# — это позиция курсора и \%V — это совпадает внутри выделения. Можно использовать и замену без замены: :.,42s/Francesca//gc. Модификатор g предписывает искать всё, а не только первое вхождение на строке, а c — спрашивать, делать ли замену. Замену делать не будем, прерывая поиск через q или продолжая через n.

Найденное подсвечивается, если выставлен флаг hlsearch. Подсветку можно убрать командой :noh (:nohlsearch).

Флаг incsearch, если выставлен, означает поиск по ходу набора искомого выражения. Которое заодно и подсвечивается. Ввод все равно надо нажать, но можно отменить поиск, увидев всё, что было надо. Курсор в этом случае никуда не двигается. Если Вим скомпилирован с поддержкой времени, то поиск не будет тратить более полусекунды, а то это довольно утомительно.

Например, если у вас написано что-то вроде Free France Francesca и вы набираете /Fr — подсвечено Fr в слове Free, далее от /Fra до /France подсвечены эти буквы в названии страны, наконец /Frances — вы нашли что искали.

Удачи в поисках, коллеги!

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

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