13

One of the things I miss from vim is being able to type in a substitution command that will work over multiple lines, for example:

:/begin/,/end/s/foo/bar/g

The above command substitutes "foo" for "bar" starting with the first line containing "begin" and ending with the next line after that containing "end".

Is there a way to do something similar in emacs?

3 Answers 3

7

evil provides a stripped-down version of ex, so it's probably best to presume that it's not an exact drop-in. However, the example you provided works out of the box, provided that point is prior to the first line (ie, the begin line in your example).

1
  • In vim the search would also start at point, so that sounds like what I was looking for. Thanks! Oct 21, 2014 at 13:46
10

Here is one way of doing it that uses built-in functionality only:

  1. With point in the line that contains first occurrence of begin, press C-SPC.

  2. Move to next occurrence of end:

    C-s end RET

  3. Replace foo with bar:

    M-% foo RET bar RET !

This makes use of the fact that query-replace will work on the active region instead of the whole buffer if there is one.


Of course, you can also define a custom command:

(defun replace-from-to (beg end str repl)
  (interactive "sBegin: \nsEnd: \nsString: \nsReplacement: ")
  (save-excursion
    (goto-char (point-min))
    (let ((start-pos (search-forward beg))
          (end-pos (search-forward end)))
      (replace-string str repl nil start-pos end-pos))))

This command will always search from the beginning of the buffer, so point can be after begin/foo/end when you invoke it.

Set up a key binding for it via:

(global-set-key (kbd "C-c r") 'replace-from-to)
5

In general, this is something that you would use narrow-to-region for.

You move the cursor (for example, by searching) to the beginning of the region and press C-SPC, then move to the end of the region and type M-x narrow-to-region. Now you can issue any search and replace commands that you want and they will only apply to narrowed part of the buffer. Once you're done, type M-x widen to restore the buffer content.

2
  • 4
    If begin/end are delimiters in a programming language, you can likely use C-M-Space to run mark-sexp to select the region in one command.
    – dgtized
    Oct 21, 2014 at 6:56
  • 1
    Default bindings: C-x n n (narrow-to-region) and C-x n w (widen).
    – itsjeyd
    Oct 21, 2014 at 7:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.