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?

Dan
  • 32,584
  • 6
  • 98
  • 168
Larry Coleman
  • 1,465
  • 2
  • 11
  • 10

3 Answers3

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)
itsjeyd
  • 14,586
  • 3
  • 58
  • 87
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).

Dan
  • 32,584
  • 6
  • 98
  • 168
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.

  • 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 '14 at 06:56
  • 1
    Default bindings: `C-x n n` (`narrow-to-region`) and `C-x n w` (`widen`). – itsjeyd Oct 21 '14 at 07:26