In Emacs, how to replace only with matching lines

For example: In VIM,

test sample replace test1 replace sample test2 

: g / sample / s / replace / test3 / - will replace "replace" only with the corresponding lines of "sample"

 test sample test3 test1 replace sample test2 

In VIM, you can replace only with inconsistent lines: v / sample / s / replace / test3 - replaces "replace" only with inconsistent lines that do not contain a "pattern"

 test sample replace test1 test3 sample test2 

How can I do something higher using emacs?

+4
source share
6 answers

Are you using Emacs 24? If so, you can use the built-in-edit-mode:

  • First, use one of the executable functions to get a buffer of strings matching your pattern:
    Mx occur RET (pattern) RET
  • Now press e to enter I / O mode to make interactive changes only on these lines.
  • Search and replacement.
  • Finally, Cc Cc to exit edit-mode, and q to reject the buffer that occurred.

There are third-party libraries for performing similar tricks in earlier versions of Emacs. I believe moccur-edit is one of them, but I have never used it.

edit: Regarding the second part of your question, although I am not familiar with the more direct way to achieve this, we can crack the same method to achieve it:

  • Mx occur RET . RET to get a buffer containing all lines
  • Cx Cq do rewrite buffer
  • Mx flush-lines RET (pattern) RET to delete matching lines
  • Cx Cq to make the buffer read-only again.
  • e to call edit-mode-mode (and then continue as before ...)
+15
source

I don’t think there is something built in there, but some elisp can do this:

 (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))))) 
+1
source

Use Icicles search and replace .

The main idea of Icicles search is to first define a search for contexts and then search in these contexts using patterns such as substrings and regular expressions. And you can just as easily find non- contexts (text outside contexts) as contexts that address your second question.

In this case, the search contexts are strings containing sample . This regular expression defines contexts:. .*sample.* , Since . matches any character except a newline.

For this search, you do not want to replace the entire search context, so you set the icicle-search-replace-whole-candidate-flag parameter to nil. By default, it is not equal to zero - you just need to press M-_ (once) to switch it. This does what matches your current minibuffer input being replaced with text, as opposed to having the whole context replaced).

You can visit any of the contexts (lines containing sample ) that you want, in any order. You can cycle through some or all of them if you wish. You can even sort contexts in a variety of ways, for easy comparison or reordering. (Sorting does not change your text in any way - contexts are sorted in the *Completions* buffer.)

But here you are really interested in the contexts that contain replace , so you type replace in the minibuffer. Only those contexts remain candidates. If you change the minibuffer input, the set of search queries --- relevant contexts --- dynamically change. Again, you can visit any of the matching contexts in any order, cycle between them, etc.

Here are the steps:

  • C-`to start the search for sockets.
  • You will be offered a regular expression that defines contexts. You will enter .*sample.* , Then press RET .
  • Press S-TAB to see the contexts highlighted in your file and listed in the *Completions* buffer. Search contexts are candidates for completion.
  • You enter replace to narrow down the contexts to those that contain replace .
  • You press M-_ (Meta underline) to toggle the cancellation of the entire context OFF (if it is currently on, it is by default).
  • Press C-down ( down arrow) to go to the first matching context.
  • You press S-RET to replace the part of the context that matches your current input ( replace ).
  • Since you have not yet identified a replacement, you will be prompted to do so. You enter test3 .
  • This replaces the first occurrence of replace . You press S-RET again to replace the next, and again to replace the next, etc.

Note that this allows you to replace multiple replace entries in the same context one by one.

If you know that you want to replace all occurrences of replace , in step 9 you can simply press M- | , to do this.

Replacement is only on request. You are essentially just looking. You decide which search queries to visit. In the example I gave you cyclically used among search queries using C-down , but you could just as easily visit only certain hits.

And when you visit the search hit, you decide whether to replace there. You do not ask for each hit in turn and are forced to answer y or n , etc., As in query-replace .

(If after filtering there is only one search context, for example, only one line with sample and replace , you will immediately fall into this context, instead of being able to replace it.)

To search for non-contexts instead of contexts, i.e. text that is outside the line containing the sample , after <search> hit CM- ~ once during the search to switch the search inside / outside the contexts. (The switch takes effect starting from the next search, and not from the place where you pressed CM- ~ .)

(An alternative approach, with some differences, is grep for strings containing sample , then press C- `in *grep* buffer, then proceed as above --- IOW, use grep to define search contexts.)

+1
source

You can use the search / replace regluar expression like this:

 Mx query-replace-regexp (or CM-%) \(sample.*\)replace RET \1test3 

This will replace with test3 on all lines with sample preceding replace .

This is not exactly what you requested (where sample can be anywhere on the line).

0
source
  • Mx replace-regexp (or query-replace-regexp )
  • Matching pattern: replace\(.*sample.*\)\|\(sample.*?\)replace\(.*\) Sample replace\(.*sample.*\)\|\(sample.*?\)replace\(.*\)
  • Replacement text: \2test3\1\3

This approach only handles the first part of the question. The second part will probably require that Lisp code be written, since Emacs regular expressions do not include lookahead statements.

0
source

The most obvious answer to this question is still missing ...

evil mode

If you use evil-mode , you can use the same commands :g ( :global ) and :v ( :vglobal ) ex in Emacs.

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

warning: Do not end the command in a slash or it violates the behavior of these commands. A slash followed by one or more flags is excellent.

-1
source

Source: https://habr.com/ru/post/1384001/


All Articles