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
  • 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, 2015 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, 2015 at 19:38

3 Answers 3

3

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
  • 1
    Actually, after gUgn, you just need .
    – D. Ben Knoble
    Oct 29, 2019 at 12:28
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).

4
  • Yes, but I would like to perform an arbitrary command at every match. Jul 2, 2015 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, 2015 at 18:10
  • 2
    Forgo the capture group as we can use \0/&. e.g. :'a,'bs/\<[whnm]\>/\U&/g. Jul 2, 2015 at 18:12
  • @Peter Rincker - Yes, that's even nicer!
    – VanLaser
    Jul 2, 2015 at 18:16
0

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:

Vrvirksomhed.virksomhedMetadata.nyesteNavn.navn

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

1
  • 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, 2019 at 11: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.