19

I have a file with a line that looks like this:

foofoo.xy.barbar

I want to change the xy to gh. I tried to do 2r -> gh, but obviously that didn't work, as it replaced the xy with gg and then moved my cursor one spot to the left.

Is there a way to do this without entering insert mode, or without using a lot more keystrokes (e.g. :s/xy/gh/)?

4
  • 2
    R enters Replace Mode. :help replace-mode for more information.
    – alxndr
    Feb 12, 2015 at 0:55
  • I tried vt.rgh. But the result was the same as yours except for the cursor position. Feb 12, 2015 at 1:17
  • 2
    Why don't you want to enter insert mode? Something like cwgh<esc> would work fine.
    – Doorknob
    Feb 12, 2015 at 2:07
  • 1
    @durron597 I'm not sure if minimize-keystrokes is a good tag, it's usually not really what the question is about, as such. (I rejected your proposed edits) ... Perhaps you should discuss at meta? Feb 12, 2015 at 13:47

4 Answers 4

24

If the new text is the same length as the old text, Vim's replace mode is an option. From normal mode, R (that's a capital "r") brings you into replace mode. This is similar to "overwrite" in some other text editors: instead of inserting new characters like in insert mode, typing will replace the character under the cursor, and then advance to the next cursor. (Think of it like the lower-case r, but for more than just a single character at a time.) Find the documentation for replace mode with :help replace-mode.

In your case: with the cursor between the . and the x, get in to replace mode by pressing R. Now when you type g it replaces the "x" and moves to the next character, so you can type h to replace the "y". Your edit is done now, so Escape to return to to normal mode.

(This works when your replacement text is the same length as the old text, but if your replacement is longer or shorter, c might be all you need: it will replace1 the text within a movement, with the text you then type. There are many ways to do use c, for example: with the cursor between the . and x, ct.ABCEscape says to change the text (up 'til the next .) with "ABC".)


1 It'll yank the text in the movement into the unnamed/" register and then switch into insert mode, so that you can type something to replace it, and then Escape back to normal mode.

4
  • 2
    This works for this case. What if you wanted to replace those 2 chars by say 3 chars? Feb 12, 2015 at 1:19
  • 1
    Good question; amended to include a way to handle different length text.
    – alxndr
    Feb 12, 2015 at 1:22
  • Yeah, I know that way. But that way you enter Insert mode and I was curious to see if there was a way not to use Insert mode in that case. Not that I think it very useful (and yet I could be wrong). Feb 12, 2015 at 1:26
  • 1
    Prefix with a numeral n to replace up to the n-th occurence of the target character. This is useful for replacing parts of labels with the format w_x_y_z and a-b-c-d. Use f instead of t to remove the limiting character as well.
    – pkfm
    Dec 6, 2019 at 1:23
5

There are a couple ways you could do this, but the simplest I can think of is:

TL;DR

fxcw<REPLACEMENT TEXT>

Explanation

  • fx jumps you to the x (see help *f*)
  • cw says to change the word (see :h *c*, :help *w*, and :help cw for more information), removing the "xy" text and entering insert mode, letting you put whatever you want right there.
  • < REPLACEMENT TEXT > is whatever you want to replace it with - "gh" in your example.

One advantage of this approach is that it uses very commonly used text manipulation & navigation commands. Another is that "xy" could be of any length, and this would still work.

The cw works because your text object is surrounded by periods (.), which act as a boundary to the word.

If your cursor is already on the "y" character (or any character in the text to be replaced), you could use ciw<REPLACEMENT TEXT>. This tells vim to change the word you're in, even if you're not at the beginning of it. See :help text-objects for more information on ciw and text objects in general.

2
  • 1
    won't this place him in insert mode?
    – elyashiv
    Feb 12, 2015 at 12:00
  • 1
    Ah - didn't catch that part of his question. In that case, yes - R is the most appropriate solution.
    – Cody Poll
    Feb 12, 2015 at 15:53
3

Replace mode:

Rgh<Esc>

is the most obvious solution if the replacement is the same length as the original but you could also do:

2sgh<Esc>

or:

cegh<Esc>
1

:1,$s/xy/gh/g has worked for me since 1987. I interpret it to mean "From line 1 to the end ($) s-search for xy, replace with gh, do it in this 'space'.

2
  • Welcome to Vi and Vim SE and thank you for posting an answer. Any reason for not using :%s to operate on the whole buffer and save two keystrokes? That adds up to a lot if used frequently over the course of 36 years :-)
    – Friedrich
    Dec 7, 2023 at 11:08
  • Welcome to Vi and Vim! No need to "interpret": the substitute command is documented by :help :substitute in Vim and by the POSIX spec for Vi.
    – D. Ben Knoble
    Dec 7, 2023 at 19:12

Your Answer

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

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