Поиск и замена

Как и в других редакторах, в Emacs есть команды для поиска случаев появления какой-нибудь строки. Основная команда поиска необычна тем, что она является наращиваемой; она начинает поиск до того, как вы закончили набор строки поиска. Существуют также команды и для ненаращиваемого поиска, более похожие на аналогичные команды в других редакторах.

Кроме обычной команды replace-string, которая находит все случаи появления одной строки и заменяет их другой, Emacs имеет более сложную команду замены, названную query-replace, которая запрашивает в интерактивном режиме, в каких случаях надо произвести замену.

Наращиваемый поиск

Наращиваемый поиск начинается, как только вы набрали первый знак строки поиска. По мере того, как вы набираете строку поиска, Emacs показывает вам, где эта строка (в том виде, в каком вы её уже набрали) может быть найдена. Когда вы набрали достаточно знаков, чтобы определить желаемое место, вы можете остановиться. В зависимости от того, что вы собираетесь делать потом, вам может понадобиться, а может и не понадобиться прекратить поиск явно с помощью RET.

C-s
Наращиваемый поиск вперёд (isearch-forward).
C-r
Наращиваемый поиск в обратном направлении (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-r RET строка RET
Поиск строки в обратном направлении.

Чтобы начать ненаращиваемый поиск, наберите сначала 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 слова RET
Ищет слова в обратном направлении, игнорируя пунктуацию между ними.

Поиск слов -- это специальный случай ненаращиваемого поиска, и он вызывается с помощью C-s RET C-w. За этим следует строка поиска, которая всегда должна быть ограничена RET. Будучи ненаращиваемым, поиск не начинается до тех пор, пока аргумент не завершен. Этот поиск работает путем создания регулярного выражения и его поиска; смотрите раздел Поиск регулярного выражения.

Для обратного поиска слов используйте C-r RET C-w.

Прямой и обратный поиск слов реализован в командах word-search-forwar и 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'. Пока все просто. Чтобы сделать что-то нетривиальное, вам необходимо использовать один из специальных знаков. Здесь представлен их перечень.

. (Точка)
является специальным знаком, который соответствует любому одиночному знаку, за исключением перевода строки. Используя конкатенацию (сцепление), вы можете составить регулярное выражение, подобное `a.b', которое соответствует любой трехзнаковой строке, начинающейся с `a' и кончающейся на `b'.
*
сама по себе не является конструкцией; это постфиксный оператор, который означает, что предыдущее регулярное выражение должно быть повторено столько раз, сколько это возможно. Таким образом, `o*' соответствует любому числу букв `o' (включая нуль). `*' всегда относится к наименьшему возможному предыдущему выражению. Таким образом, `fo*' содержит повторяющуюся `о', а не `fo'. Оно совпадает с `f', `fo', `foo' и так далее. Конструкция `*' обрабатывается путем сопоставления с наибольшим количеством повторений, которое сразу может быть найдено. Затем продолжается сравнение с остатком шаблона. Если оно прошло неудачно, то происходит перебор с возвратом. Некоторые из совпадений с конструкцией с модификатором `*' сбрасываются, чтобы дать возможность поиска соответствия для остатка структуры. Например, сравнивая `ca*ar' со строкой `caaar', `a*' сначала ставится в соответствие со всеми тремя `а', но остаток шаблона -- это `ar', а в этом случае для подбора остается только `r', поэтому эта попытка неудачна. Следующий вариант -- это поставить в соответствие с `а*' только две буквы `а'. При таком выборе остаток регулярного выражения успешно соответствует строке.
+
это такой же постфиксный оператор, как и `*', за исключением того, что он требует, чтобы предшествующее ему выражение сопоставлялось по крайней мере один раз. Так например, `ca+r' будет соответствовать строкам `car' и `caaar', но не строке `cr', тогда как `ca*r' соответствует всем трем строкам.
?
постфиксный оператор, как и `*', но он может соответствовать предшествующему выражению либо один раз, либо ни одного. Например, `ca?r' будет соответствовать `car' или `cr' и ничему больше.
[ ... ]
это набор знаков, который начинается `[' и завершается `]'. В простейшем случае совпадающий набор формируют знаки между этими скобками. Таким образом, `[ad]' соответствует либо одной `a', либо одному `d', а `[ad]*' соответствует любой строке, составленной просто из `а' и `d' (включая пустую строку), из всего этого следует, что `c[ad]*r' соответствует `cr', `car', `cdr', `caddaar' и так далее. Вы также можете включить в множество знаков интервалы, написав два знака, разделенные `-'; таким образом, `[a-z]' соответствует любой строчной букве ASCII. Интервалы могут быть свободно перемешаны с отдельными знаками, как в `[a-z$%.]', что соответствует любой строчной букве ASCII, или `$', или `%' или точке. Заметим, что специальные знаки регулярных выражений внутри такого множества больше не являются специальными. Внутри знакового множества существуют совершенно другой набор специальных знаков: `]', `-' и `^'. Чтобы включить в знаковый набор `]', вы должны поставить его первым. Например, `[]а]' соответствует `]' или `а'. Чтобы включить `-', напишите `-' первым или последним знаком в наборе или поместите его после указания интервала. Таким образом, `[]-]' соответствует `]' и `-'. Чтобы включить в набор знак `^', пишите его где угодно, но не первым. Если вы задаёте интервал при поиске без учета регистра, вы должны либо написать оба конца интервала заглавными буквами, либо оба строчными, либо оба они не должны быть буквами. Поведение интервала с концами, заданными в разных регистрах, определено плохо и может быть изменено в будущих версиях Emacs.
[^ ... ]
`[^' начинает дополнительный набор знаков, который соответствует любому знаку, исключая описанные в нём. Таким образом, `[^a-z0-9A-Z]' соответствует всем знакам, исключая буквы и цифры. `^' не является специальным в наборе знаков, если он не стоит первым. Знак, следующий за `^', трактуется так, как если бы он был первым (иными словами, `-' и `]' здесь не являются специальными). Дополнительный набор знаков может соответствовать знаку новой строки, если он не упоминается как один из несовпадающих знаков. Это противоречит способу обработки регулярных выражений в таких программах, как grep.
^
это специальный знак, который соответствует пустой строке, но только в начале строки сопоставляемого текста. В противном случае, сравнение не удастся. Таким образом, `^foo' соответствует `foo', которая встречена в начале строки.
$
подобен `^', но сравнение происходит только в конце строки. Таким образом, `xx*$' соответствует строке из одного или более `x' в конце строки.
\
имеет две функции: отменяет особый смысл специальных знаков (включая `\') и вводит дополнительные специальные конструкции. Так как `\' отменяет особый смысл специальных знаков, то `\$' -- это регулярное выражение, которое соответствует только `$', а `\[' -- регулярное выражение, которое соответствует только `[', и так далее.

Замечание: для исторической совместимости специальные знаки трактуются как обычные знаки, если они находятся в контексте, в котором их специальный смысл не имеет значения. Например, `*foo' трактует `*' как обыкновенный, так как не существует предыдущего выражения, на которое может подействовать `*'. Плохо быть зависимым от этого правила; лучше всегда явно отменять особый смысл специальных знаков независимо того, где они находятся.

В большинстве случаев `\', за которым следует любой знак, соответствует только этому знаку. Однако, существует несколько исключений: двухзнаковые последовательности, начинающиеся с `\', имеющие особый смысл. Второй знак в такой последовательности всегда обычный, когда встречается сам по себе. Здесь представлена таблица конструкций с `\'.

\|
описывает альтернативу. Два регулярных выражения a и b с `\|' между ними формируют выражение, которое соответствует любому из них в отдельности: либо a, либо b. Это работает так: сначала пробуется a, и если соответствие не найдено, пробуется b. Таким образом, `foo\|bar' соответствует либо `foo', либо `bar', но не другой строке. `\|' применяется к самым большим охватывающим выражениям. Только охватывающие скобки `\( ... \)' могут ограничить группирующую силу `\|'. Существует возможность полного обратного восстановления для обработки многократных использований `\|'.
\( ... \)
группирующая конструкция, которая служит для трех целей:
  1. Чтобы отделить набор альтернатив `\|' от других операций. Таким образом, `\(foo\|mar\)x' соответствует либо `foox', либо `marx'.
  2. Чтобы ограничить сложное выражение для действия постфиксных операторов `*', `+' и `?'. Таким образом, `ba\(na\)*' соответствует `bananana' и так далее с любым (нулевым или большим) числом строк `na'.
  3. Чтобы отметить соответствующую подстроку для будущей ссылки.
Это последнее применение не является следствием идеи ограничения группы; это отдельное свойство, которое определено как второе значение той же самой конструкции `\( ... \)'. На практике между этими двумя значениями не оказывается противоречий.
\n
соответствует тексту, совпавшему с n-ным появлением конструкции `\( ... \)'. После конца конструкции `\( ... \)' сопоставление запоминает начало и конец текста, совпавшего с этой конструкцией. Затем, позднее в регулярном выражении, вы можете использовать `\', за которым следует цифра n, чтобы сказать: "сопоставить с том же текстом, который совпал с n-ным появлением конструкции `\( ... \)'". Строкам, соответствующим первым девяти конструкциями `\( ... \)', появляющимся в регулярном выражении, присваиваются номера от 1 до 9 в том порядке, в каком в регулярном выражении появились открывающие скобки. Конструкции от `\1' до `\9' могут использоваться для ссылки на текст конструкции `\( ... \)' с этим номером. Например, `\(.*\)\1' соответствует любой строке, не содержащей знаков перевода строки, которая состоит из двух одинаковых половин. `\(.*\)' соответствует первой половине, которая может быть любой, но `\1', что идет следом, должна соответствовать точно такому же тексту. Если для какой-нибудь конструкции `\( ... \)' найдено более одного соответствия (что может легко произойти, если за ней следует `*'), то запоминается только последнее совпадение.
\`
соответствует пустой строке, но только в начале буфера или строки, где происходит поиск.
\'
соответствует пустой строке, но только в конце буфера или строки, где происходит поиск.
\=
соответствует пустой строке, но только в точке.
\b
соответствует пустой строке, если эта конструкция находится в начале или конце слова. Таким образом, `\bfoo\b' соответствует любому появлению `foo' как отдельного слова. `bballs?\b' соответствует `ball' или `balls' как отдельным словам. `\b' находит соответствие в начале или конце буфера, независимо от того, какой текст идет далее.
\B
соответствует пустой строке, если только она находится не в начале или конце слова.
\<
соответствует пустой строке, если она находится в начале слова. `\<' находит соответствие в начале буфера, но только если затем идет знак, являющийся частью слова.
\>
соответствует пустой строке, если она находится в конце слова. `\>' находит соответствие в конце буфера, но только если буфер завершается знаком, являющимся частью слова.
\w
соответствует любому знаку, являющемуся частью слова. Какие именно это знаки, определяет синтаксическая таблица. Смотрите раздел Синтаксическая таблица.
\W
соответствует любому знаку, не являющемуся частью слова.
\sc
соответствует любому знаку, чей синтаксис определяется кодом c. Здесь c -- это знак, который представляет собой синтаксический код, например, это `w' для части слова, `-' для пробельных знаков, `(' для открывающей скобки, и так далее. Вы можете обозначить пробельный знак (который может быть переводом строки) либо как `-', либо одним пробелом.
\Sc
соответствует любому знаку, чей синтаксис не определяется кодом c.

Конструкции, имеющие отношение к словам и синтаксису, управляются установками в синтаксической таблице (смотрите раздел Синтаксическая таблица).

Далее представлено сложное регулярное выражение, используемое 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 (смотрите раздел Управление расшифровкой сокращения).

Безусловная замена

M-x replace-string RET строка RET новая-строка RET
Заменяет каждое вхождение строки на новую-строку.
M-x replace-regexp RET regexp RET новая-строка RET
Заменяет каждое совпадение с regexp на новую-строку.

Чтобы заменить каждый случай вхождения `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, замещение происходит без изменения регистра.

Замена с подтверждением

M-% строка RET новая-строка RET
M-x query-replace RET строка RET новая-строка RET
Заменяет некоторые вхождения строки на новую-строку.
C-M-% regexp RET новая-строка RET
M-x query-replace-regexp RET regexp RET новая-строка RET
Заменяет некоторые совпадения с regexp на новую-строку.

Если вы хотите заменить только некоторые экземпляры `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, вы можете набрать следующее:

SPC
чтобы заменить это вхождение на новую-строку.
DEL
чтобы перейти к следующему вхождению, не заменяя это.
, (Запятая)
чтобы заменить это вхождение и показать результат. Затем у вас запрашивают ввод ещё одного знака, чтобы узнать, что делать дальше. Так как замена уже произведена, то DEL и SPC в этой ситуации эквивалентны; обе переходят к следующему вхождению. Вы можете набрать в этом месте C-r (смотрите ниже), чтобы изменить замененный текст. Вы можете также набрать C-x u, чтобы отменить сделанную замену; эта команда выходит из query-replace, так что если вы хотите делать дальнейшие замены, вы должны использовать C-x ESC ESC RET, чтобы запустить замену заново (смотрите раздел Повтор команд минибуфера).
RET
чтобы выйти без осуществления дальнейших замен.
. (Точка)
чтобы заменить этот экземпляр и затем выйти без продолжения поиска следующих вхождений.
!
чтобы заменить все оставшиеся экземпляры без повторных запросов.
^
чтобы вернуться к положению предыдущего вхождения (или к тому, что им было), если вы изменили его по ошибке. Это делается при помощи выталкивания из списка пометок. Можно использовать только один `^' подряд, так как во время работы query-replace хранится только одна предыдущая позиция замены.
C-r
чтобы войти в новый уровень рекурсивного редактирования, в том случае, когда экземпляр нуждается скорее в редактировании, чем просто в замене его новой-строкой. Когда вы сделаете это, выйдите из этого уровня рекурсивного редактирования, набрав C-M-c, чтобы перейти к следующему вхождению. Смотрите раздел Уровни рекурсивного редактирования.
C-w
чтобы удалить это вхождение и потом войти в новый уровень рекурсивного редактирования, как в C-r. Используйте рекурсивное редактирование для вставки текста и замены удалённого вхождения строки. Когда вы закончите, выйдите из этого уровня рекурсивного редактирования с помощью C-M-c, чтобы перейти к следующему вхождению.
C-l
чтобы восстановить изображение экрана. Потом вы должны набрать ещё один знак, чтобы указать, что делать с этим вхождением.
C-h
чтобы просмотреть сообщение, резюмирующее эти варианты. Потом вы должны набрать ещё один знак, чтобы указать, что делать с этим вхождением.

Некоторые другие знаки являются синонимами перечисленных выше: 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.

M-x occur RET regexp RET
Выводит перечень, показывающий каждую строку буфера, которая содержит совпадение с regexp. Числовой аргумент задаёт число строк контекста, которые должны быть напечатаны перед и после каждой сравниваемой строки; значений по умолчанию -- не печатать контекст. Чтобы ограничить поиск частью буфера, сузьтесь до этой части (смотрите раздел Сужение). Буфер `*Occur*', в который записывается вывод, служит в качестве меню для поиска вхождений в их оригинальном контексте. Щелкните Mouse-2 на вхождении, перечисленном в `*Occur*', или поместите там точку и нажмите RET; это переключит в буфер, где делался поиск, и переместит точку к оригиналу выбранного вхождения.
M-x list-matching-lines
Синоним для M-x occur.
M-x count-matches RET regexp RET
Печатает число совпадений с regexp после точки.
M-x flush-lines RET regexp RET
Удаляет каждую строку, следующую после точки и содержащую совпадение с regexp.
M-x keep-lines RET regexp RET
Удаляет каждую строку, следующую после точки и не содержащую совпадение с regexp.

Кроме того, вы можете использовать из Emacs программу grep для поиска совпадений с регулярным выражением в группе файлов, а затем обратиться к найденным совпадениям последовательно или в произвольном порядке. Смотрите раздел Поиск с Grep под Emacs.

Назад |  Вперед |  Содержание



Распространение материалов сайта означает, что распространитель принял условия лицензионного соглашения.
Идея и реализация: © Владимир Довыденков и Анатолий Камынин,  2004-2024