I want to match (search) all C code comments in a file in e.g.

   enum {
       /* Foo is so cool, why can't we all be more like foo? */
       /* but bar is mysterious and suave, like the James Bond of enum 
          and variable names. */

So, I want a regex that will match both the single and multiline C comments delimited by /* and */.


The problem with pure regex based solutions, is that there would be a few false-positives, like in:


char const* p = "/*";

/* bar */

/// foo

char const* e = "*/";

/* in strings would be matched as well.

I though at first that we could get around it with [* and ]*, but unfortunately, they are also regex based.

Though, we can have the correct behaviour with {skip} parameter in search()

:echo search('/\*\_.\{-}\*/\|//' ,'',0,0, 'synIDattr(synID(line("."), col("."), 0), "name") =~ "\\cstring"')

which is best defined as a mapping

" for a mapping defined this way, we have to double the '\' before the '|' to express the _or_
nnoremap <silent> [< :<c-u>call search('/\*\_.\{-}\*/\\|//' ,'',0,0, 'synIDattr(synID(line("."), col("."), 0), "name") =~ "\\cstring"')<cr>
  • Wouldn’t it also be possible to execute a search that only stops on specific highlight groups (eg cComment, or those that match comment case-insensitive)?
    – D. Ben Knoble
    Apr 7 at 12:39
  • 2
    @D.BenKnoble If we inverse the skip value it may be possible if there aren't any strange side effects on the bordaries of the syntax groups . Also, there are some comments groups "without" comment but doxygen in their name Apr 7 at 13:03
  • Might be worth noting that a relatively recent version of Vim is required to get the skip param. I don't have it in 8.2.486 (my other local build is 8.2.2434 which has it).
    – B Layer
    Apr 8 at 19:28
  • @BLayer My bad. I thought it was older than that. Apr 8 at 20:12

I already know but I searched the web and couldn't find the definitive answer for VIM (just every other regex language), and I won't remember this again in a week, so I am documenting it here.

And the answer is...


Lemme break it down.

To match the first \* you have to escape both the \ and the * so that's \/\*

To match the end you have to do the same for *\ so that's \*\/ at the end.

You want to include everything between those, this is where it gets tricky. You can use \_.* to match everything between (the \_ makes it multiline), but this is too greedy and will match everything between the first \* and the last *\.

To make it non-greedy use \_.\{-} instead of \_.* (\{-} uses a "shortest match first" algorithm) and so we get the above vim search regex.

  • 1
    Can't you do the standard *? instead of {-}?
    – wizzwizz4
    Apr 7 at 17:21
  • 1
    @wizzwizz4, you're confusing with perl. There is no such standard pattern in vim. See :h perl-patterns Apr 8 at 13:20

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.