Как и в других редакторах, в Emacs есть команды для поиска случаев появления какой-нибудь строки. Основная команда поиска необычна тем, что она является наращиваемой; она начинает поиск до того, как вы закончили набор строки поиска. Существуют также команды и для ненаращиваемого поиска, более похожие на аналогичные команды в других редакторах.
Кроме обычной команды replace-string
, которая находит все
случаи появления одной строки и заменяет их другой, Emacs имеет более
сложную команду замены, названную query-replace
, которая
запрашивает в интерактивном режиме, в каких случаях надо произвести
замену.
Наращиваемый поиск начинается, как только вы набрали первый знак строки поиска. По мере того, как вы набираете строку поиска, Emacs показывает вам, где эта строка (в том виде, в каком вы ее уже набрали) может быть найдена. Когда вы набрали достаточно знаков, чтобы определить желаемое место, вы можете остановиться. В зависимости от того, что вы собираетесь делать потом, вам может понадобиться, а может и не понадобиться прекратить поиск явно с помощью RET.
isearch-forward
).
isearch-backward
).
C-s начинает наращиваемый поиск. C-s считывает знаки с клавиатуры и располагает курсор в первом месте появления знаков, которые вы набрали. Если вы наберете C-s и затем F, то курсор встанет справа после первой найденной `F'. Наберите О, и увидите, что курсор встал за первой найденной `FO'. После еще одной О курсор встанет за первой `FOO', находящейся за местом, с которого вы начали поиск. На каждом шаге текст буфера, совпадающий со строкой поиска, подсвечивается, если терминал может это сделать; текущая строка поиска обновляется на каждом шаге в эхо-области.
Если вы сделали ошибку в наборе строки поиска, то вы можете сбросить знаки с помощью DEL. Каждый DEL отменяет последний знак строки поиска. Этого не происходит до тех пор, пока Emacs не будет готов считать следующий вводимый знак; сначала знак, который вы хотите сбросить, должен быть либо найден, либо нет. Если же вы не хотите ждать, пока это произойдет, используйте C-g так, как описано ниже.
Когда вы будете удовлетворены достигнутым местом, вы можете набрать RET, что остановит поиск, оставляя курсор там, куда его поместила команда поиска. Любая команда, не имеющая специального значения при поиске, также останавливает поиск и затем выполняется сама. Таким образом, набор C-a привел бы к выходу из поиска и затем передвинул бы курсор в начало строки. RET необходим только в том случае, если следующая команда, которую вы хотите набрать, является печатным знаком, DEL, RET или другим управляющим знаком, имеющим особое значение во время работы поиска (C-q, C-w, C-r, C-s, C-y, M-y, M-r или M-s).
Иногда вы ищете слово `FOO' и находите его, но это не то, что вам нужно. Было второе `FOO', о котором вы забыли, находящееся перед тем, которое вы ищете. В этом случае наберите C-s еще раз, чтобы продвинуться к следующему появлению строки поиска. Это можно проделывать неограниченное число раз. Если вы проскочили, то можете отменить некоторые число знаков C-s с помощью DEL.
После выхода из поиска вы можете снова искать ту же самую строку, просто набрав C-s C-s: первый C-s -- это ключ, который запускает наращиваемый поиск, а второй C-s означает "повтор поиска".
Чтобы вы могли снова использовать более ранние строки поиска, существует список поиска. Команды M-p и M-n передвигают по списку, чтобы вы могли подобрать нужную строку для повторного поиска. Эти команды оставляют выбранную строку поиска в минибуфере, где вы можете ее отредактировать. Для завершения редактирования и начала поиска наберите C-s или C-r.
Если ваша строка вообще не найдена, то эхо-область говорит `Failing I-Search'. Курсор располагается после того места, где Emacs нашел из вашей строки всё, что смог. Таким образом, если вы ищете `FOOT', а такой строки нет, вы можете увидеть курсор после `FOO' в слове `FOOL'. С этого места вы можете сделать несколько вещей. Если ваша строка неправильно набрана, вы можете что-то стереть из нее и исправить. Если вы довольны найденным местом, вы можете набрать RET или любую другую команду Emacs, чтобы "принять то, что предложил этот поиск", или вы можете набрать C-g, что уничтожит из строки поиска знаки, которые не были найдены (`Т' в `FOOT'), оставляя те, что нашлись (`FOO' в `FOOT'). Второй C-g в этом месте отменяет поиск полностью, возвращая точку туда, где она была, когда поиск начался.
Если строка поиска содержит заглавную букву, то поиск производится с учетом регистра. Если вы удалите заглавные буквы из строки поиска, эта особенность исчезает. Смотрите раздел Поиск и регистр букв.
Если поиск был неудачным и вы просите повторить его, набирая C-s еще раз, то он начинается снова с начала буфера. Повторение неудачного поиска в обратном направлении при помощи команды C-r начинает новый поиск с конца. Такой поиск называется круговым. Как только это произошло, в подсказке поиска появляется слово `Wrapped'. Если вы пройдете через точку, где начался поиск, это слово заменяется на `Overwrapped', что означает, что вы снова проходите через уже виденные вами совпадения.
Знак "выхода" C-g поступает во время поиска особым образом. Что именно он делает, зависит от статуса поиска. Если поиск нашел то, что вы хотели, и ожидает ввода, то C-g полностью отменяет поиск. Курсор возвращается туда, откуда вы начали поиск. Если C-g набирается, когда в строке поиска есть ненайденные знаки -- Emacs все еще ищет их, или он не смог их найти -- тогда эти ненайденные знаки сбрасываются из строки поиска. Сброс этих знаков делает поиск успешным, и он ждет дальнейшего ввода, таким образом, второй C-g отменит поиск полностью.
Чтобы найти символ перевода строки, введите C-j. Для поиска другого управляющего знака, такого как control-S или возврат каретки, вы должны отменить их специальное значение, набирая перед ними C-q. Эта функция C-q аналогична ее назначению как команды для вставки (смотрите раздел Вставка текста): она заставляет трактовать следующий знак так, как в этом контексте трактовался бы любой "обычный" знак. Вы также можете задать знак по его восьмиричному коду: введите C-q и затем последовательность восьмиричных цифр.
Вы можете изменить направление поиска на обратное при помощи C-r. Вам следует поступить так, если поиск оказался неудачным, потому что место, с которого вы его начали, находилось слишком близко к концу файла. Повторение C-r продолжает поиск следующих случаев появления в обратном порядке, а C-s начинает поиск опять вперед. C-r в поиске может быть отменена при помощи DEL.
Если вы заранее знаете, что вам нужно вести поиск в обратном порядке,
то чтобы начать поиск, вы можете использовать C-r вместо
C-s, так как C-r также является ключом, запускающим команду
(isearch-backward
) для поиска в обратном порядке. Обратный поиск
находит совпадения, которые расположены перед начальной точкой, так же
как поиск вперед находит совпадения, начинающиеся после точки, где поиск
начался.
Знаки C-y и C-w могут использоваться в наращиваемом поиске для захвата текста из буфера в строку поиска. Это делает удобным поиск другого случая появления того текста, который находится в точке. C-w копирует слово после точки в строку поиска, продвигая точку вперед через это слово. Следующая команда C-s для повторения поиска будет затем искать строку, включающую это слово. C-y подобна C-w, только копирует в строку поиска весь остаток текущей строки. И C-y, и C-w преобразуют копируемый текст к нижнему регистру, если поиск сейчас ведется без учета регистра; таким образом поиск остается регистронезависимым.
Команда M-y копирует в строку поиска текст из списка уничтожений. Она использует тот же текст, который был бы восстановлен командой C-y. Смотрите раздел Восстановление.
Когда вы выходите из наращиваемого поиска, метка устанавливается в то место, где точка была до начала поиска. Это удобно для возврата к этому месту. В режиме Transient Mark наращиваемый поиск устанавливает метку, не активизируя ее, если только метка уже не активна.
Чтобы настроить специальные знаки, которые понимает наращиваемый
поиск, измените их привязки в таблице ключей isearch-mode-map
.
Для получения перечня привязок посмотрите документацию на
isearch-mode
с помощью C-h f isearch-mode RET.
Наращиваемый поиск на медленных терминалах использует модифицированный способ отображения, который разработан так, чтобы занимать как можно меньше времени. Вместо показа буфера в каждом месте, до которого добрался поиск, он создает новое окно, состоящее из одиночной строки, и использует его для показа найденной строки. Это окно из одной строки вступает в игру, как только точка выходит за пределы текста, который уже находится на экране.
Когда вы прерываете поиск, однострочное окно убирается. Только в этот момент Emacs перерисовывает окно, в котором производился поиск, чтобы отобразить новое положение точки.
Такой стиль отображения используется, когда скорость терминала в бодах
меньше или равна значению переменной search-slow-speed
, чье
начальное значение равно 1200.
Количество строк, показываемых при поиске на медленном терминале,
управляется переменной search-slow-window-lines
. Ее обычное
значение равно единице.
В Emacs также есть удобные команды ненаращиваемого поиска, которые требуют от вас полностью набрать строку поиска до начала работы.
Чтобы начать ненаращиваемый поиск, наберите сначала C-s RET. Эта команда входит в минибуфер для считывания строки поиска; ограничьте эту строку с помощью RET, и поиск начнется. Если строка не будет найдена, команда поиска выдает ошибку.
Способ работы C-s RET заключается в следующем: C-s запускает наращиваемый поиск, который специально запрограммирован так, что запускает ненаращиваемый поиск, если заданный вами аргумент является пустым. (Такой пустой аргумент в других случаях был бы бесполезен). C-r RET работает аналогично.
Однако, запрошенный с помощью C-s RET ненаращиваемый поиск
не запускает непосредственно search-forward
. Первым делом
проверяется, не будет ли следующим знаком C-w, что запустит поиск
слов.
Прямой и обратный ненаращиваемый поиск осуществляются командами
search-forward
и search-backward
. Эти команды могут быть
привязаны к ключам обычным способом. Возможность их запуска через
наращиваемый поиск имеет исторические причины и, помимо этого,
существует для того, чтобы вам не нужно было находить для них подходящие
последовательности ключей.
Поиск по словам применяется для отыскания последовательности слов независимо от того, как эти слова разделены. Более подробно, вы набираете строку из нескольких слов, используя для их разделения одиночные пробелы, и эта строка может быть найдена, даже если в оригинале слова разделены несколькими пробелами, переводами строки, либо любыми знаками препинания.
Поиск слов полезен при редактировании печатных документов, подготовленных в программах для форматирования текста. Если вы редактируете, просматривая уже напечатанную, отформатированную версию, то вы не можете сказать, где прерывается строка в исходом файле. При помощи же поиска слова вы можете искать, не имея этой информации.
Поиск слов -- это специальный случай ненаращиваемого поиска, и он вызывается с помощью C-s RET C-w. За этим следует строка поиска, которая всегда должна быть ограничена RET. Будучи ненаращиваемым, поиск не начинается до тех пор, пока аргумент не завершен. Этот поиск работает путем создания регулярного выражения и его поиска; смотрите раздел Поиск регулярного выражения.
Для обратного поиска слов используйте C-r RET C-w.
Прямой и обратный поиск слов реализован в командах
word-search-forward
и word-search-backward
. Эти команды
могут быть привязаны к ключам обычным способом. Возможность их запуска
через наращиваемый поиск существует по историческим причинам и для того,
чтобы вам не нужно было находить для них подходящие последовательности
ключей.
Регулярное выражение (regexp, если кратко) -- это образец, который обозначает набор строк, возможно, и неограниченный набор. В GNU Emacs вы можете искать следующее совпадение с регулярным выражением как наращиваемым способом, так и простым.
Наращиваемый поиск регулярного выражения производится набором
C-M-s (isearch-forward-regexp
). Эта команда считывает
наращиваемую строку поиска, так же, как C-s, но трактует ее как
регулярное выражение, а не ищет в тексте буфера точное совпадение.
Каждый раз, когда вы добавляете текст в строку поиска, вы делаете
регулярное выражение длиннее, и ищется уже новое регулярное выражение.
Вызов C-s с префиксным аргументом (значение не играет роли) ---
это другой способ произвести прямой поиск регулярного выражения. Чтобы
запустить поиск регулярного выражения в обратном направлении,
используйте C-M-r (isearch-backward-regexp
) или C-r с
префиксным аргументом.
Все управляющие знаки, которые делают специальные вещи в рамках обыкновенного наращиваемого поиска, имеют те же самые функции и в наращиваемом поиске регулярного выражения. Набор C-s или C-r немедленно после начала поиска восстанавливает последнее регулярное выражение, использованное для наращиваемого поиска регулярного выражения; это говорит о том, что наращиваемый поиск регулярного выражения и строки имеют независимые значения по умолчанию. Они также имеют раздельные списки поиска, доступ к которым вы можете получить с помощью M-p и M-n.
Если при наращиваемом поиске регулярного выражения вы наберете SPC, он будет совпадать с произвольной последовательностью пробельных знаков, включая переводы строк. Если вам нужен только один пробел, введите C-q SPC.
Обратите внимание, добавление знаков к регулярному выражению при наращиваемом поиске может вернуть курсор назад и начать поиск снова. Например, если вы искали `foo' и добавляете `\|bar', курсор вернется назад, если первый `bar' предшествовал первому `foo'.
Ненаращиваемый поиск регулярного выражения осуществляется функциями
re-search-forward
и re-search-backward
. Вы можете
запустить их с помощью M-x, или привязать их к ключам или вызывать
через наращиваемый поиск регулярного выражения с помощью C-M-s
RET и C-M-r RET.
Если вы используете команды наращиваемого поиска регулярного выражения
с префиксным аргументом, они производят обычный поиск строки, как
isearch-forward
и isearch-backward
. Смотрите раздел Наращиваемый поиск.
Регулярные выражения имеют синтаксис, в котором несколько знаков служат специальными конструкциями, а остальные -- это обыкновенные знаки. Обыкновенный знак -- это простое регулярное выражение, которое соответствует этому знаку и никакому больше. Специальными знаками являются `$', `^', `.', `*', `+', `?', `[', `]' и `\'. Любые другие знаки, появляющиеся в регулярном выражении, являются обыкновенными, если только им не предшествует `\'.
Например, `f' -- это неспециальный знак, значит он обыкновенный, поэтому `f' -- это регулярное выражение, которое соответствует строке `f' и никакой другой. (Оно не соответствует строке `ff'). Аналогично, `о' -- это регулярное выражение, которое соответствует только `о'. (Когда различия в регистре игнорируются, эти регулярные выражения также совпадают с `F' и `O', но мы рассматриваем это как обобщение понятия "та же строка", а не как исключение.)
Любые два регулярных выражения a и b могут быть сцеплены. Результатом является регулярное выражение, совпадающее со строкой, в которой a соответствует некоторому началу этой строки, а b соответствует остатку строки.
В качестве простого примера мы можем сцепить регулярные выражения `f' и `o', чтобы получить регулярное выражение `fo', которое соответствует только строке `fo'. Пока все просто. Чтобы сделать что-то нетривиальное, вам необходимо использовать один из специальных знаков. Здесь представлен их перечень.
grep
.
Замечание: для исторической совместимости специальные знаки трактуются как обычные знаки, если они находятся в контексте, в котором их специальный смысл не имеет значения. Например, `*foo' трактует `*' как обыкновенный, так как не существует предыдущего выражения, на которое может подействовать `*'. Плохо быть зависимым от этого правила; лучше всегда явно отменять особый смысл специальных знаков независимо того, где они находятся.
В большинстве случаев `\', за которым следует любой знак, соответствует только этому знаку. Однако, существует несколько исключений: двухзнаковые последовательности, начинающиеся с `\', имеющие особый смысл. Второй знак в такой последовательности всегда обычный, когда встречается сам по себе. Здесь представлена таблица конструкций с `\'.
Конструкции, имеющие отношение к словам и синтаксису, управляются установками в синтаксической таблице (смотрите раздел Синтаксическая таблица).
Далее представлено сложное регулярное выражение, используемое Emacs
для распознавания конца предложения вместе с любыми пробельными
знаками, которые идут следом. Оно дано в синтаксисе Лиспа, чтобы дать
вам возможность отличить пробелы от знаков табуляции. В синтаксисе
Лиспа, константная строка начинается и заканчивается двойными кавычками.
`\"' обозначает двойные кавычки как часть регулярного выражения,
`\\' обозначает обратную косую черту, `\t' обозначает знак
табуляции, а `\n' -- знак новой строки.
"[.?!][]\"')]*\\($\\|\t\\| \\)[ \t\n]*"
Здесь последовательно содержатся четыре части: набор знаков, соответствующий точке, `?' или `!'; набор знаков, соответствующий парным квадратным скобкам, кавычкам или круглым скобкам, повторяемым любое число раз; альтернатива, заключенная в скобки с обратными косыми чертами, которая соответствует концу строки, табуляции или двум пробелам; и набор знаков, соответствующий любым пробельным знакам, повторяющимся любое число раз.
Чтобы ввести это регулярное выражение интерактивно, вы напечатали бы TAB, чтобы получить знак табуляции, и C-j, чтобы получить знак перевода строки. Вы также печатали бы одиночные обратные косые черты как есть, а не дублировали бы их в соответствии с синтаксисом Лиспа.
Все виды наращиваемого поиска в Emacs обычно игнорируют регистр текста, в котором происходит поиск, если вы задали текст в нижнем регистре. Таким образом, если вы запросили поиск `foo', то совпадениями считаются и `Foo', и `foo' . Регулярные выражения, и в частности наборы знаков, также включаются в это правило: `[aB]' соответствовало бы `a', или `A', или `b' или `B'.
Заглавная буква в любом месте строки наращиваемого поиска делает этот поиск регистрозависимым. Таким образом, поиск `Foo' не найдет `foo' или `FOO'. Это применяется также и к поиску регулярного выражения. Этот эффект исчезает, если вы удалили заглавные буквы из строки поиска.
Если вы установите переменную case-fold-search
равной
nil
, все буквы должны будут совпадать точно, включая регистр.
Эта переменная своя для каждого буфера; ее изменение затрагивает только
текущий буфер, но существует значение по умолчанию, которое вы тоже
можете изменить. Смотрите раздел Локальные переменные. Эта переменная
применяется также и к ненаращиваемому поиску, включая те его
разновидности, которые осуществляются командами замены (смотрите раздел Команды замены)
и командами поиска в истории минибуфера (смотрите раздел История минибуфера).
Глобальные команды поиска и замены не нужны в Emacs так часто, как в других редакторах(2), но они доступны. Кроме простой команды M-x replace-string, которая аналогична такой же команде в большинстве редакторов, существует команда M-x query-replace, которая для каждого появления образца спрашивает вас, надо ли его заменять.
Команды замены обычно работают с текстом от точки до конца буфера;
однако, в режиме Transient Mark они действуют на область, когда метка
активна. Все команды замены заменяют одну строку (или регулярное
выражение) одной строкой замены. Можно выполнить параллельно несколько
замен, используя команду expand-region-abbrevs
(смотрите раздел Управление расшифровкой сокращения).
Чтобы заменить каждый случай вхождения `foo' после точки на `bar', используется команда M-x replace-string с двумя аргументами `foo' и `bar'. Замещение происходит только в тексте после точки, так, если вы хотите охватить весь буфер, вы должны сначала отправиться в его начало. Все экземпляры вплоть до конца буфера будут заменены; чтобы ограничиться заменой в части буфера, сузьте его до этой части перед выполнением замены (смотрите раздел Сужение). В режиме Transient Mark, если область активна, замена ограничена этой областью (смотрите раздел Режим Transient Mark).
Когда вы выходите из replace-string
, точка остается на месте
последней замены. Значение точки в момент, когда была запущена команда
replace-string
, запоминается в списке пометок. C-u
C-SPC перемещает вас обратно.
Числовой аргумент ограничивает замену совпадениями, которые окружены ограничителями слов. Значение аргумента роли не играет.
Команда M-x replace-string заменяет точные совпадения с
одиночной строкой. Аналогичная команда replace-regexp
замещает
любое совпадение с заданным образцом.
В replace-regexp
, новая-строка не обязательно должна быть
константой: она может ссылаться на все или часть того, что соответствует
регулярному выражению regexp. `\&' в новой-строке
означает полный замещаемый текст. `\n', где n -- это
цифра, означает то, что было поставлено в соответствие n-ной
заключенной в скобки группе в регулярном выражении regexp. Чтобы
включить в новый текст знак `\', вы должны ввести `\\'.
Например,
M-x replace-regexp RET c[ad]+r RET \&-safe RET
заменит (например) `cadr' на `cadr-safe' и `cddr' на
`cddr-safe'.
M-x replace-regexp RET \(c[ad]+r\)-safe RET \1 RET
делает обратное преобразование.
Если первый аргумент в команде замены набран в нижнем регистре, во
время поиска вхождений для замены регистр игнорируется -- при условии,
что case-fold-search
не равна nil
. Если
case-fold-search
установлена в значение nil
, регистр
учитывается во всех типах поиска.
Кроме того, когда аргумент новая-строка весь или частично
написан строчными буквами, команды замены пытаются сохранить образец
использования регистра в каждом вхождении. Таким образом, команда
M-x replace-string RET foo RET bar RET
заменяет `foo' в нижнем регистре на `bar' в нижнем регистре,
`FOO' в верхнем регистре на `BAR', а `Foo' с первой
заглавной буквой на `Bar'. (Три эти альтернативы: все строчные
буквы, все заглавные и первая заглавная -- единственные варианты,
которые может распознать replace-string
.)
Если в строке подстановки использованы буквы верхнего регистра, то они
остаются такими при каждой вставке этого текста. Если буквы верхнего
регистра используются в первом аргументе, то второй аргумент всегда
вставляется в том виде, в котором он дан, без изменения регистра.
Аналогично, если переменная case-replace
или
case-fold-search
установлена равной nil
, замещение
происходит без изменения регистра.
Если вы хотите заменить только некоторые экземпляры `foo' на
`bar', но не все, вы не можете использовать обыкновенную
replace-string
. Вместо этого используется M-%
(query-replace
). Эта команда находит экземпляры `foo' один
за другим, отображает каждый экземпляр и спрашивает вас, надо ли его
заменять. Числовой аргумент говорит query-replace
, что нужно
рассматривать лишь те экземпляры, которые окружены знаками-разделителями
слов. Эта команда сохраняет регистр так же, как и
replace-string
, при условии, что case-replace
не равна
nil
, как это обычно и бывает.
За исключением запроса подтверждения, query-replace
работает
точно так же, как replace-string
, а query-replace-regexp
--- как replace-regexp
. Эта команда запускается при помощи
C-M-%.
Когда вам показывают вхождение строки или совпадение с регулярным выражением regexp, вы можете набрать следующее:
query-replace
, так что
если вы хотите делать дальнейшие замены, вы должны использовать C-x
ESC ESC RET, чтобы запустить замену заново
(смотрите раздел Повтор команд минибуфера).
query-replace
хранится только
одна предыдущая позиция замены.
Некоторые другие знаки являются синонимами перечисленных выше: y, n и q эквивалентны SPC, DEL и RET.
Кроме этих знаков, любой другой выходит из query-replace
и
снова считывается как часть последовательности ключей. Таким образом,
если вы напечатаете C-k, она выйдет из query-replace
и
уничтожит текст до конца строки.
Чтобы перезапустить query-replace
, когда вы уже из нее вышли,
используйте C-x ESC ESC, которая повторит
query-replace
, так как она использовала минибуфер для чтения
аргументов. Смотрите раздел Повторение команды.
Смотрите также раздел Преобразование имен файлов в Dired, чтобы узнать о командах Dired для переименования, копирования или создания ссылок на файлы путем замены в их именах совпадений с регулярным выражением.
Здесь представлены некоторые другие команды, которые находят
совпадения с регулярными выражениями. Все они действуют от точки до
конца буфера, и все они игнорируют при сопоставлении регистр, если
образец не содержит заглавных букв, а case-fold-search
отлична от
nil
.
Кроме того, вы можете использовать из Emacs программу grep
для поиска совпадений с регулярным выражением в группе файлов, а затем
обратиться к найденным совпадениям последовательно или в произвольном
порядке. Смотрите раздел Поиск с Grep под Emacs.