I have 'a and 'b bounding some lines of text. I want to convert all the w, h, n, and m variables to upper case. A sample line:

f(w,h,n,m) | w <= 0 | h <= 0 | n < 0 | m < 0 = 0

It seems to me that this should work:

:'a,'b g/\<[whnm]\>/normal ~

This doesn't work. It matches the line, but does not match the individual variables. It leaves the cursor at the beginning of the line and capitalizes the f there. How do I make it perform the ~ action at every match in the range?

I know this particular example can be done simply with a regex substitution. I don't want to do that. I want to run an arbitrary command at every location that matches a search pattern, which seems like something obvious to do, but so far appears impossible to do in vim.

  • 2
    Your problem is :global operates on entire lines only, and not the matching part. So you're running ~ for every line (which should convert the first character, f, to F). No time to write a more expanded answer right now, but at least you know your problem ;-) Jul 2 '15 at 17:54
  • To me, it seems like vim's problem instead of my problem. I've been using vim exclusively for a couple of years, and have recently begun to try to step up my vim sophistication level. I keep bumping into this butterfly every once in a while, and I'd like to kill it and pin it to the page. Jul 2 '15 at 19:38

Try this:

:'a,'b s/\v(<[whnm]>)/\U\1/g

Short expl.:

\v - very magic

(...) - create 1st group

\U\1 - make 1st group uppercase

Good references: vimregex, W.A.Zintz's articles

To operate on each match, repeatedly, using a "normal-mode" command, you could do this instead:

/\C\v<[whnm]> ENTER
~       (<- or any other command(s) operating on the match)
qqn.q   (<- create a macro with "go to next result, repeat command(s) above")
20@q    (<- repeat the macro 20 times)

You can use any number instead of 20, ideally bigger than than the number of matches, the condition being that your command applied to the match makes it a non-match for a second search round - when the search hits bottom and starts again from the top (hence the \C - case sensitive search).

  • Yes, but I would like to perform an arbitrary command at every match. Jul 2 '15 at 18:02
  • 1
    The simplest would be to perform a search \v<[whnm]>, press ~ (or whatever command), and then it is just a matter of hitting n. repeatedly (and that could be automated).
    – VanLaser
    Jul 2 '15 at 18:10
  • 2
    Forgo the capture group as we can use \0/&. e.g. :'a,'bs/\<[whnm]\>/\U&/g. Jul 2 '15 at 18:12
  • @Peter Rincker - Yes, that's even nicer!
    – VanLaser
    Jul 2 '15 at 18:16

You can use the the gn motion to operation on the current search pattern match and repeat your operation via the . command. Example:

  • /foo - set pattern
  • gUgn - uppercase (gU) the current match, gn
  • n move to the next match
  • . to repeat your last operation, gUgn

Note: I find this method doesn't work the best with single character matches as gn will select the current charter to the next match.

You will need Vim 7.4 to use gn motion and 7.4.110+ to use gUgn.

For more help see:

:h gn
:h gU

There is also a nice Vimcasts episode on this: Operating on search matches using gn

  • 1
    Actually, after gUgn, you just need .
    – D. Ben Knoble
    Oct 29 '19 at 12:28

You can write a macro that operates on the pattern you want and run it like 500 times. For instance I had a bunch of lines like this one:


That I wanted to CamelCase, so i wrote this small macro: /\.xvU, and ran it until no more changes.

  • 1
    Welcome to this site! Another possible way to write your macro is to first do your search /\. and then use n in the macro, potentially that allows you to correct your search pattern on the fly without having to record the macro again.
    – statox
    Oct 29 '19 at 11:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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