РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ VIM - Брам Мооленаар

Всякие умные штучки

Сочетая разные команды можно заставить Vim делать с текстом практически всё, что угодно. Мы покажем в этой главе несколько таких полезных возможностей, используя команды, которые обсуждались в предыдущих главах, плюс несколько дополнительных команд.

12.1    Замена слова
12.2    Замена "Фамилия, Имя" на "Имя Фамилия"
12.3    Сортировка списка
12.4    Обратный порядок строк
12.5    Подсчёт слов
12.6    Поиск в справочнике man
12.7    Удаление лишних пробелов
12.8    Найти строки, где используется слово

Следующая глава: Быстрый набор в командной строке
Предыдущая глава: Восстановление после аварии
Содержание: Руководство пользователя Vim


12.1 Замена слова

Команда substitute может быть использована для замены одного слова на другое по всему тексту:

:%s/три/3/g

Диапазон "%" указывает на весь файл. Флаг "g" в конце команды вызывает замену всех слов в строке.

Однако, если в файле также имеются слова вроде "сотри", то они также будут заменены, например, "со3". Это явно не то, что нам нужно. Чтобы этого избежать, воспользуемся элементом "\<" в шаблоне, чтобы отметить начало слова:

%s/\<три/3/g

С другой стороны, ошибка все равно неизбежна, в словах вроде "тринадцать". Чтобы отметить конец слова в шаблоне, воспользуемся элементом "\<":

%s/\<три\>/3/g

Если вы пишите программу, то, возможно, захотите заменить "три" только в комментариях. Чтобы долго не мучиться с изобретением шаблона, используйте флаг "c", чтобы команда substitute спрашивала вас о каждой замене:

:%s/\<four\>/4/gc
ЗАМЕНА В НЕСКОЛЬКИХ ФАЙЛАХ

Предположим, что вы хотите заменить слово в нескольких файлах. Для этого можно открыть каждый файл и набрать требуемую команду вручную. Однако, гораздо быстрее воспользоваться записью команды и её последующим воспроизведением.

Пусть у вас имеется каталог с файлами исходных текстов программ на C++, имена которых заканчиваются на ".cpp". В этих файлах имеется функция "GetResp", которую вы хотели бы переименовать в "GetAnswer".

vim *.cpp Запустите Vim со списком аргументов, состоящим из всех файлов C++. Перед вами откроется первый файл.
qq Начните запись команды в регистр q.
:%s/\<GetResp\>/GetAnswer/g Сделайте необходимые замены в первом файле.
:wnext Сохраните этот файл и перейдите к следующему.
q Остановите запись.
@q Выполните команду в регистре q, в результате чего будут произведены необходимые замены и выполнится команда ":wnext". Убедитесь, что не возникает сообщений об ошибке.
999@q Выполните команду в регистре q на остальных файлах.

На последнем файле вы увидите сообщение об ошибке, поскольку ":wnext" не может перейти к следующему файлу. В результате, выполнение будет остановлено, а вся требуемая работа будет выполнена.

Замечание: При воспроизведении записанной последовательности команд ошибка вызывает остановку исполнения. Поэтому убедитесь, что во время записи команды ошибок не возникает.

Здесь есть одна деталь: если в одном из файлов .cpp нет слова "GetResp", то вы увидите сообщение об ошибке и выполнение макроса будет остановлено. Чтобы этого избежать, добавьте к команде замены флаг "e"

:%s/\<GetResp\>/GetAnswer/ge

Флаг "e" сообщает ":substitute", что отсутствие соответствий шаблону не считается ошибкой.


12.2 Замена "Фамилия, Имя" на "Имя Фамилия"

У вас есть список имён в следующем виде:

Пупкин, Василий ~
Сидоров, Пётр ~

Вы хотите, чтобы список выглядел так:

Василий Пупкин ~
Пётр Сидоров ~

Эта операция может быть проделана одной-единственной командой:

:%s/\([^,]*\), \(.*\)/\2 \1/

Давайте разберёмся. Само собой, это команда замены substitute. Диапазон "%" указывает на все строки в файле.

Аргументы команды substitute указываются в форме "/откуда/куда/". Косая черта разделяет шаблон "откуда" и строку "куда". Вот что содержит шаблон "откуда":

                                                      \([^,]*\), \(.*\) ~
    Первая часть между \( \) соответствует "Фамилии"  \(     \)
        соответствует любому символу, кроме запятой     [^,]
        повторяется любое количество раз                    *
    соответствует символу "," буквально                        ,
    Вторая часть между \( \) соответствует "Имени"             \(  \)
        соответствует любому символу                        .
        повторяется любое количество раз                     *

В части "куда" у нас есть "\2" и "\1". Это называется обратными ссылками. Они ссылаются на текст, который соответствует частям "\( \)" в шаблоне. "\2" относится к соответствию со вторым "\( \)", т.е. соответствует "Имени". "\1" ссылается на первое по счёту "\( \)", т.е. соответствует "Фамилии".

Вы можете использовать до девяти обратных ссылок в аргументе "куда" команды substitute. "\0" указывает на весь шаблон соответствия. В команде substitute также имеется еще несколько специальных компонентов, см. |спецсимволы_для_замены|.


12.3 Сортировка списка

В Makefile часто встречаются списки файлов. Например:

OBJS = \ ~
    version.o \ ~
    pch.o \ ~
       getopt.o \ ~
       util.o \ ~
       getopt1.o \ ~
       inp.o \ ~
       patch.o \ ~
       backup.o ~

Для сортировки этого списка, пропустите текст через внешнюю программу-фильтр sort:

/^OBJS
j
:.,/^$/-1!sort

Vim переходит к первой строке, которая начинается со слова "OBJS", затем перемещает курсор на строку вниз и пропускает через фильтр все строки вплоть до следующей пустой строки. Можно было бы также выделить строки в Визуальном режиме и затем использовать "!sort". Так получается нагляднее, но если строк слишком много, то требует больше усилий.

Результат работы команды-фильтра:

OBJS = \ ~
       backup.o ~
       getopt.o \ ~
       getopt1.o \ ~
       inp.o \ ~
       patch.o \ ~
       pch.o \ ~
       util.o \ ~
       version.o \ ~

Обратите внимание, что обратная косая черта в конце строки указывает на продолжение строки. После сортировки расположение этого символа оказалось нарушено! Строка "backup.o", которая находилась в конце списка, не имела на конце обратной косой черты, а теперь, когда она находится в верхней части списка, должна её иметь.

Самое простое решение будет добавить обратную косую при помощи команды "A \<Esc>". Что касается косой черты на последней строке, то она не мешает, если после неё есть пустая строка. В этом случае, при повторной сортировке, проблемы больше не возникнет.


12.4 Обратный порядок строк

Команда |:global| в сочетании с командой |:move| может переместить все строки по очереди в позицию перед первой строкой, чтобы получился файл с обратным порядком строк. Команда выглядит так:

:global/^/m 0

Сокращённо:

:g/^/m 0

Регулярное выражение "^" соответствует началу строки, даже в том случае, если строка пустая. Команда |:move| перемещает соответствующие строки в позицию после мифической нулевой строки, так, что текущая строка становится первой строкой в файле. Поскольку команда |:global| не обращает внимания на изменяющиеся номера строк, то она продолжает считывать файл строка за строкой и переносить строки снизу вверх.

Это также будет работать и в диапазоне строк. Переместите курсор в положение над первой строкой и отметьте эту позицию при помощи команды "mt". Затем переместите курсор к последней строке в диапазоне и введите команду:

:'t+1,.g/^/m 't

12.5 Подсчёт слов

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

Для подсчёта слов в файле используйте команду

g CTRL-G

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

Кол 1 из 0; стр. 141 из 157; слово 748 из 774; байт 4489 из 4976 ~

Вы можете видеть на каком слове вы находитесь в данный момент (748) и сколько слов всего в файле (774).

Если текст, в котором надо посчитать слова, занимает не весь файл, то вместо того, чтобы проводить в уме вычисления разности между двумя значениями в разных позициях файла, достаточно выделить необходимый фрагмент в Визуальном режиме, и затем дать команду g CTRL-G. Вот как может выглядеть результат:

Выделено 5 из 293 строк; 70 из 1884 слов; 359 из 10928 байт ~

Другие способы подсчёта слов, строк и других вещей обсуждаются в |подсчёт_элементов_текста|.


12.6 Поиск в справочнике man

При редактировании сценария оболочки или программы на языке C вам иногда требуется посмотреть для какой-нибудь команды или функции страницу справочника man (на Unix). Давайте попробуем простой способ: подведите курсор к необходимому слову и нажмите

K

Vim выполнит внешнюю программу "man" с данным словом в качестве аргумента. Если страница найдена, то она будет показана. При этом используется стандартная программа-пейджер, например "more". Когда вы начитаетесь, нажмите <Enter> для возврата в Vim.

К сожалению, при этом способе нельзя видеть страницу man и текст, над которым вы работаете, одновременно. Существует способ заставить страницу man появиться прямо в окне Vim. Сначала загрузите модуль для типа фала man:

:runtime! ftplugin/man.vim

Если вы собираетесь часто пользоваться этой возможностью, то поместите указанную команду в файл vimrc. Теперь можно читать man прямо в Vim! Попробуйте:

:Man csh

Само собой, синтаксис будет подсвечиваться. Для возврата в окно с текстом, над которым вы работаете, введите CTRL-W w.

Для поиска страницы man из какого-нибудь конкретного раздела, используйте обычный синтаксис. Например, для "echo(3)": >

:Man 3 echo

Для перехода к другой странице man, нажимайте CTRL-] на ссылке. Дальнейшие вызовы команд ":Man" будут использовать то же самое окно.

Чтобы показать страницу для слова, на котором находится курсор, пользуйтесь командой:

\K

(Если вы переопределили <Leader>, то пользуйтесь своим значением вместо обратной косой черты). Например, если вы хотите посмотреть, что возвращает "strstr()" во время редактирования строки:

if (strstr(input, "aap") == ) ~

то подведите курсор к "strstr" и введите "\K". Откроется окно, со страницей справочника для strstr().


12.7 Удаление лишних пробелов

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

:%s/\s\+$//

Мы используем диапазон "%", чтобы это работало на всех строках в файле. Шаблон, соответствие которому ищет команда ":substitute" -- "\s\+$". Этот шаблон соответствует 1 или большему количеству (\+) пробельных символов (\s) перед концом строки ($). Мы объясним, как придумывать такие шаблоны позднее, в |usr_27.txt|.

Часть "куда" команды substitute пустая: "//". Таким образом, замена происходит ни на что, удаляя все пробелы, совпадающие с шаблоном.

Другой пример бестолкового использования пробелов -- перед символом табуляции. Часто эти пробелы можно удалить без всякого вреда, но не всегда! Поэтому, лучше всего делать это вручную, при помощи команды поиска

/<Space><Tab>

Попробуйте удалить найденные пробелы командой "x", следя за тем, чтобы ширина пробела не изменялась. Если это произойдёт, то вам возможно потребуется вставить ещё один символ табуляции. Для перехода к следующему соответствию, нажмите "n". Операцию нужно будет повторить до тех пор, пока больше не останется соответствий шаблону.


12.8 Найти строки, где используется слово

Если вы пользуетесь UNIX, то можете использовать комбинацию Vim и команды grep для редактирования всех файлов, содержащих заданное слово. Это чрезвычайно полезно, если вы работаете над программой и хотите посмотреть или отредактировать все файлы, содержащие определённую переменную.

Предположим, например, что вы хотите отредактировать все файлы с кодом C, содержащие слово "frame_counter". Для этого используйте такую команду:

vim `grep -l frame_counter *.c`

Посмотрим на эту команду повнимательнее. Команда grep ищет заданное слово в серии файлов. Поскольку указан ключ -l, то команда выведет лишь список файлов, в которых встречается указанное слово, без вывода строк с соответствиями. Вместо слова можно было бы использовать любое регулярное выражение.

Замечание: регулярные выражения в команде grep и в редакторе Vim не всегда совпадают по синтаксису.

Вся команда целиком заключается в обратные одинарные кавычки. Это указывает оболочке UNIX, что нужно выполнить команду и подставить результат её выполнения в командную строку. В итоге, результат выполнения команды grep, список файлов, передаётся в качестве списка аргументов редактору. Для перемещения между файлами можно использовать команды ":next", ":first" и т.п.

ПОИСК ВСЕХ СТРОК

Указанная выше команда лишь находит файлы, в которых встречается заданное слово. Вам также потребуется найти это слово в самих файлах.   В Vim есть встроенная команда, которая позволяет искать в нескольких файлах заданную строку. Например, если вы хотите найти во всех исходных текстах C строку "error_string", введите команду

:grep error_string *.c

В результате Vim откроет первый файл, где встречается "error_string" и поместит курсор на первой строке с соответствием. Для перехода к следующей строке, независимо от того, в каком файле она находится, используйте команду ":cnext". Для перехода к предыдущему соответствию предусмотрена команда ":cprev". Чтобы посмотреть список всех соответствий пользуйтесь командой ":clist".

Команда ":grep" использует внешнюю программу grep (на Unix) или findstr (на Windows). Название используемой программы можно изменить, настроив опцию 'grepprg'.


Следующая глава: Быстрый набор в командной строке
Авторские права: см. Авторские права