3

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 ;-) – Martin Tournoij 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. – NovaDenizen Jul 2 '15 at 19:38
3

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. – NovaDenizen 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
  • 1
    Forgo the capture group as we can use \0/&. e.g. :'a,'bs/\<[whnm]\>/\U&/g. – Peter Rincker Jul 2 '15 at 18:12
  • @Peter Rincker - Yes, that's even nicer! – VanLaser Jul 2 '15 at 18:16
2

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

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.