Как рефакторить код с помощью регулярных выражений в Vim
Узнайте, как проводить рефакторинг кода с помощью регулярных выражений в Vim, из этой статьи Руслана Осипова, инженера-программиста Google, заядлого путешественника и блоггера по совместительству. Он начал публиковать личные заметки Vim в 2012 году и все больше интересовался тонкостями редактора и его применениями для оптимизации рабочих процессов разработки.
Поиск или замена регулярными выражениями
Регулярные выражения (или регулярные выражения) прекрасны, и вы должны знать, как их использовать. Vim, как принято среди реализаций регулярных выражений, имеет свою собственную разновидность регулярных выражений. Однако, как только вы выучите один, вам будет комфортно со всеми ними. Сначала поговорим об обычной (то есть обычной) команде поиска и замены. Обратите внимание, что вы можете найти необходимые файлы кода для этой статьи по адресу https://github.com/PacktPublishing/Mastering-Vim/tree/master/Chapter06.
Поиск и замена
Vim поддерживает поиск и замену с помощью команды :substitute, чаще всего сокращенно :s. По умолчанию : s заменяет одну подстроку другой в текущей строке. Он имеет следующий формат:
:s/<find-this>/<replace-with-this>/<flags>
Флаги необязательны. Чтобы попробовать, откройте animal_farm.py, перейдите к строке, содержащей кошку (например, с помощью /cat), и выполните следующее:
:s/cat/dog
Это заменяет первое вхождение cat в текущей строке:
Теперь давайте посмотрим на флаги, которые вы можете передать команде замены:
• g — глобальная замена: замена всех вхождений шаблона, а не только первого.
• c — подтверждать каждую замену: запрашивать пользователя перед заменой текста.
• e — не показывать ошибки, если совпадений не найдено.
• i — игнорировать регистр: сделать поиск нечувствительным к регистру.
• I — сделать поиск чувствительным к регистру.
Вы можете смешивать и сочетать их (кроме i и I) по своему усмотрению. Например, бег /cat/dog/gi превратит строку cat.Cat() в dog.dog(). Перед :substitute может стоять диапазон, указывающий, над чем работать. Чаще всего с :substitute используется диапазон %, что делает
работать с текущим файлом. Например, если бы мы хотели заменить каждый экземпляр животного в файле существом, мы бы выполнили следующее:
:%s/animal/creature/g
Если вы попробуете это сделать на animal_farm.py, вы увидите, что каждое вхождение животного было заменено существом:
Команда :substitute удобно сообщает нам, сколько совпадений было заменено в строке состояния внизу экрана. Кажется, мы только что завершили очень простой рефакторинг! :substitute поддерживает больше диапазонов. Вот некоторые из них:
• цифры — номер строки
• $ — последняя строка в файле
• % — весь файл (один из самых часто используемых)
• /search-pattern/ — позволяет найти строку для работы.
• ?backwards-search-pattern? — делает то же самое, что и предыдущий флаг, но выполняет поиск в обратном направлении.
Кроме того, вы можете комбинировать диапазоны с помощью ; оператор. Например, 20;$ позволит вам искать от строки 20 до конца файла. Чтобы продемонстрировать, следующая команда будет искать и заменять каждое вхождение животного на существо из строки 12 до строки включительно, где встречается собака:
:12;/dog/s/animal/creature/g
Два экземпляра животного были заменены в строках 13 и 14, но не в строках 10 и 21:
Вы также можете выбрать диапазон в визуальном режиме и запустить без каких-либо явных диапазонов для работы с выделенным текстом. См. :help cmdline-ranges для получения дополнительной информации о диапазонах. Чаще всего вы обнаружите, что заменяете все вхождения во всем файле, выполнив следующее:
:%s/find-this/replace-with-this/g
При замене текста вы можете искать только все слово целиком. Вы можете использовать < и > для этой цели. Например, в следующем файле мы можем искать /animal (:set hlsearch включен для выделения всех результатов), но мы также получаем результаты, которые нас не совсем интересуют, например животных:
Однако, если мы будем искать /<животное>, мы сможем сопоставить только целые слова без ложного обнаружения животных, как показано ниже:
Операции с файлами с использованием arglist
Arglist позволяет вам выполнять одну и ту же операцию с несколькими файлами без предварительной загрузки их в буферы. Arglist предоставляет несколько команд, а именно:
• :arg определяет список аргументов.
• :argdo позволяет выполнить команду для всех файлов в списке аргументов.
• :args отображает список файлов в списке аргументов.
Например, если бы мы хотели заменить все экземпляры животных в каждом файле Python (рекурсивно), мы бы сделали следующее:
:arg **/*.py
:argdo %s/\<animal\>/creature/ge | update
Эта команда работает следующим образом:
• :arg <шаблон> добавляет набор файлов, соответствующих шаблону, в список аргументов (каждый аргумент в списке аргументов также имеет соответствующий буфер).
• **/*.py — это подстановочный знак для каждого файла .py, рекурсивно начинающийся с текущего каталога.
• :argdo выполняет команду для каждого элемента в списке аргументов.
• %s/
:update эквивалентен :write, но сохраняет файл только в том случае, если буфер был изменен. Вам нужно использовать :update в командах arglist, потому что Vim не любит, когда вы переключаете буферы без сохранения их содержимого. Альтернативой может быть использование :set hidden, чтобы отключить эти предупреждения и сохранить все файлы в конце, запустив :wa.
Попробуйте, и вы увидите, что каждое вхождение слова было заменено (вы можете проверить, запустив git status или git diff, если у вас есть репозиторий, зарегистрированный в Git). Вы также можете просмотреть содержимое списка аргументов, выполнив следующую команду без каких-либо аргументов:
:args
На самом деле список Arglist остался со времен Vi — он использовался так же, как сегодня мы используем буферы. Буферы расширяются за счет списка аргументов: каждая запись списка аргументов находится в списке буферов, но не каждый буфер находится в списке аргументов.
Технически вы также можете использовать :bufdo для выполнения операции над каждым открытым буфером (поскольку записи списка аргументов отражаются в списке буферов). Однако я бы не советовал этого делать, так как есть риск запустить команду для буферов, которые вы непреднамеренно открыли до заполнения списка аргументов.
Если вы нашли эту статью интересной, вы можете изучить Освоение Vim чтобы сделать Vim (или его ответвление, Neovim) вашим первым выбором при написании приложений на Python и других языках программирования. Освоение Vimрассмотренный Брэмом Муленааром, создателем Vim, рассказывает об использовании Vim и Neovim, демонстрирует соответствующие плагины и обучает Vimscript.