В Emacs, Как заменить только на совпадающие строки - PullRequest
4 голосов
/ 01 декабря 2011

Например: в VIM,

test
sample replace
test1
replace
sample test2

: г / образец / с / заменить / тест3 / - заменит "заменить" только в соответствующих строках на "образец"

test
sample test3
test1
replace
sample test2

В VIM замена только на несоответствующих строках может быть выполнена с помощью: v / sample / s / replace / test3 - заменит «заменить» только на несоответствующих строках, которые не содержат «выборку»

test
sample replace
test1
test3
sample test2

Как это можно сделать с помощью emacs?

Ответы [ 6 ]

17 голосов
/ 01 декабря 2011

Используете ли вы Emacs 24 perchance?Если это так, вы можете использовать встроенный режим возникновения-редактирования:

  • Сначала используйте одну из функций возникновения, чтобы получить буфер строк, соответствующих вашему шаблону:
    Mx occur RET (рисунок) RET
  • Теперь нажмите e , чтобы войти в режим обработки при редактировании и выполнить интерактивное редактирование этих файлов.Только строки.
  • Поиск и замена.
  • Наконец, Cc Cc для выхода из режима возникновения-редактирования и q чтобы закрыть буфер возникновения.

Существуют сторонние библиотеки для выполнения подобных трюков в более ранних версиях Emacs.Я считаю, что moccur-edit является одним из них, но я никогда не использовал его.

править: Что касается второй части вашего вопроса, хотя я не знаком с более прямым способом достижения этого, мыможет взломать этот же метод для достижения этого:

  • Mx occur RET . RET , чтобы получить буфер, содержащий все строки
  • Cx Cq , чтобы создать возможность записи в буфер
  • Mx flush-lines RET (шаблон) RET для удаления совпадающих строк
  • Cx Cq для повторного создания буфера только для чтения
  • e для вызова режима возникновения-редактирования (а затем продолжения, как раньше ...)
1 голос
/ 01 декабря 2011

Использование Сосульки Поиск и Замена .

Основная идея Сосульки поиск должен сначала определить поиск контексты , а затем искать в этих контекстах, используя шаблоны, такие как подстроки и регулярные выражения.И вы можете так же легко искать не -контекстов (текст вне контекста), как контексты, которые касаются вашего второго вопроса.

В этом случае контекстами поиска являются строки, содержащие sample.Это регулярное выражение определяет контексты: .*sample.*, поскольку . соответствует любому символу, кроме новой строки.

Для этого поиска вы не хотите заменять весь контекст поиска, поэтому вы должны установить для параметра icicle-search-replace-whole-candidate-flag значение nil,По умолчанию оно не равно нулю - вам просто нужно нажать M -_ (один раз), чтобы переключить его.Это делает все, что соответствует вашему текущему вводу минибуфера, текстом, который будет заменен, а не тем, что весь контекст будет заменен тем, что заменяется.хочу, в любом порядке.Вы можете переключаться между некоторыми или всеми из них, если хотите.Вы даже можете сортировать контексты различными способами, для простого сравнения или изменения порядка циклирования.(Сортировка никоим образом не меняет ваш текст - контексты сортируются в буфере *Completions*.)

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

Вот шаги:

  1. C-`,чтобы начать поиск сосулек.
  2. Вам будет предложено регулярное выражение, которое определяет контексты.Вы набираете .*sample.*, затем нажимаете RET .
  3. Вы нажимаете S-TAB , чтобы увидеть контексты, выделенные в вашем файле и перечисленные в буфере *Completions*.Контекстами поиска являются кандидаты на завершение .
  4. Вы вводите replace, чтобы сузить контексты до тех, которые содержат replace.
  5. Вы нажали M-_ (подчеркивание мета), чтобы отключить замену всего контекста (при условии, что в данный момент он включен, что по умолчанию).
  6. Вы нажали C-down (управляющая стрелка вниз)чтобы перейти к первому соответствующему контексту.
  7. Вы нажимаете S-RET , чтобы заменить часть контекста, которой соответствует ваш текущий ввод (replace).
  8. Свы еще не определили замену, вам будет предложено это сделать.Вы набираете test3.
  9. , который заменяет первое вхождение replace.Вы нажимаете S-RET снова, чтобы заменить следующее, и снова, чтобы заменить следующее, и т. Д.

Обратите внимание, что это позволяет заменять несколько вхождений replace в одном и том жеконтекст, один за другим.

Если вы знаете, что хотите заменить все вхождений replace, на шаге 9 вы можете просто нажать M- | насделать это.

Замена только по требованию .По сути, вы просто ищете.Вы сами решаете, какие поисковые хиты посетить.В приведенном мной примере вы циклически переключались между поисковыми хитами, используя C-down, но вы также могли легко посещать только определенные попадания.

И когда вы посещаете поисковый хит, вы решаете, выполнять лизамена там.Вас не запрашивают за каждое попадание по очереди и заставляют ответить y или n и т. Д., Как в query-replace.

(Если после фильтрации есть только один контекст поиска, например, только одинс sample и replace, и вы сразу попадете в этот контекст, вместо того, чтобы получить возможность заменить его части.)

Для поиска не -контекстов вместо контекстов, т. Е. Текста, находящегося вне строки, содержащей sample, нажмите CM- ~ один раз во время завершения в поиск, чтобы переключить поиск внутри / вне контекста. (Переключение вступает в силу, начиная со следующего поиска, а не с того, где вы нажали C-M- ~ .)

(Альтернативный подход, с некоторыми отличиями, заключается в grep для строк, содержащих sample, затем нажмите C-` в буфере *grep*, затем действуйте, как указано выше - IOW, используйте grep для определения контекстов поиска.)

1 голос
/ 01 декабря 2011

Я не думаю, что есть что-то встроенное, но некоторые elisp могут это сделать:

(defun my-replace-on-matching-lines (&optional arg)
  "Replace text on lines that match a regexp.
With prefix arg, replace on non-matching lines."
  (interactive "P")
  (let* ((regexp (concat ".*"
                         (read-from-minibuffer
                          (concat "Replace on lines "
                                  (if arg "not " "")
                                  "matching regexp: "))))
         (replace (read-from-minibuffer "Replace: "))
         (with (read-from-minibuffer (concat "Replace " replace " with: ")))
         match)
    (save-excursion
      (goto-char (point-min))
      (while (not (eobp))
        (setq match (looking-at regexp))
        (when (if arg (not match) match)
          (while (search-forward replace (point-at-eol) t)
            (replace-match with nil t)))
        (forward-line)))))
0 голосов
/ 31 января 2017

Самый очевидный ответ на этот вопрос до сих пор отсутствовал ...

зло режим

Если вы используете evil-mode, вы можете использовать те же команды :g (:global) и :v (:vglobal) ex в Emacs.

:g/sample/s/replace/test3
:v/sample/s/replace/test3

предупреждение: Не не заканчивать команду косой чертой, иначе это нарушит поведение этих команд. Слэш, за которым следуют один или несколько флагов, подойдет.

0 голосов
/ 01 декабря 2011
  • М-х replace-regexp (или query-replace-regexp)
  • Шаблон для сопоставления: replace\(.*sample.*\)\|\(sample.*?\)replace\(.*\)
  • Текст замены: \2test3\1\3

Этот подход касается только первой части вопроса. Вторая часть, вероятно, потребует написания некоторого кода на Лиспе, поскольку регулярные выражения Emacs не включают в себя предварительные утверждения.

0 голосов
/ 01 декабря 2011

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

M-x query-replace-regexp   (or C-M-%)
\(sample.*\)replace      RET
\1test3

Это заменит replace для test3 во всех строках с sample перед replace.

Это не совсем то, что вы просили (где sample может быть где угодно в строке).

...