6

I'm not sure if I've failed at searching for the answer to this, but now I've worked it out I wanted to document it here. The problem is searching for a multiline pattern, and storing all such occurrences in a register.

I am trying to look for calls to a particular function, e.g. func(a, b, c);, so that I can extract them to a separate file. I'm doing this in Vim (rather than using, say, sed or awk), because I find Vim's searching over multiple lines syntax easiest.

If I search for a pattern, I know I can store the line(s) containing the results in a register:

:let @a=''
:g/func\s*([^;]*;/y A

Stores all the single line calls to func in @a.

Unfortunately, this doesn't quite work if I adapt this search pattern to find multiple line calls:

/func\s*(\_.\{-\}; matches multi-line calls such as:

func(a, b,
c,
d);

-- no matter how many new lines/parameters are in the way, but the corresponding global command :g/func\s*(\_.\{-\};/y A just stores the first line of each match. I can sort of understand why this happens (y yanks the line the result is on, and doesn't know it takes multiple lines).

How can I adapt the command to store all lines of each occurrence in a register?

5

It turns out something along these lines works (although there might well be better ways) -- using a substitute-without-substituting command instead of a global command:

Starting with the answer here: How to show all unique types of a pattern?

:%s/[A-Za-z]*\>/\=add(b:types, submatch(0))/ng

I went with:

let @a=''
:%s/func\s*(\_[^;]\{-\};/\=setreg('A', submatch(0)."\n")/ng

Which stores all the calls, even the entirety of multi-line ones. because the A is capitalised, it's appended, as before. The "n" means to not actually do a substitute, and for completeness "g" means all occurrences on each line.

EDIT: Previously I'd tried appending '\n' or '\r' to put each match on a new line -- but they came out literally. Instead appending "\n" puts each match on a new line. Thanks to @Jair for the new line fix -- I didn't know single and double quotes were different, and didn't think to try the other!

  • 1
    You're almost done. Just replace '\n' with "\n". Read What is the difference between single and double quoted strings? – Jair López Mar 18 '17 at 11:57
  • Brilliant -- thanks, @Jair. I'll wait a bit to see if anyone suggests a better method (it was the first time I'd come across the n option to substitute -- it feels a bit odd to use a substitute to not do a substitute! Then again, the option's there...) – Jonathan Mar 18 '17 at 13:08
1

To yank a last multiline search pattern into register with a multiline non-greedy pattern, try:

/func(\_.\{-});/norm gn"iy

then you'll have your yanked multiline pattern (between func( and );) in your @i register (print by echo @i).

Here is the command line example as per this post given func.txt input file:

$ ex +'sil /func\_.\{-});/norm gny' +'redi>>/dev/stdout|echon @"' -scq! func.txt
func(a, b,
c,
d);

Related:

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.