Привет, коллеги. Обсудим поиск поподробнее. Основы я уже излагал, а теперь пришло время для более пристального разбора.
Для поиска есть команды / и ?, включающие особую командную строку, в которой можно ввести искомый текст. Текст этот трактуется как регулярное выражение. Есть возможности для настройки: от "все символы, кроме \, означают себя" до "все символы, кроме алфавитно-цифровых, имеют особое значение". Об этой магии мы уже беседовали, и там же об учете/игнорировании регистра тоже.
Сама командная строка обладает некоторыми особыми возможностями. Есть история, для поиска своя, отделенная от истории команд. Можно переключать раскладку, так же, как в буфере (<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 — вы нашли что искали.
Удачи в поисках, коллеги!