« Back to Index

Vim: search multiple lines with line breaks using PCRE_DOTALL mode

View original Gist on GitHub

Tags: #silversearcher #ag #ack #grep #PCRE #regex #vim #lookahead #ripgrep

Ag with PCRE_DOTALL.md

As noted in this thread: https://github.com/ggreer/the_silver_searcher/issues/459#issuecomment-118785490

The trick to get the PCRE engine have . to include new lines is to prefix your pattern with ‘Perl options’ (http://www.pcre.org/original/doc/html/pcrepattern.html#SEC13).

So to get PCRE_DOTALL we need to prefix our regex pattern with (?s).

For example, consider a file test.txt with the following content:

Line 1
Line 2
Line 3

We can match all three lines using:

ag '(?s)Line 1.+Line 3' test.txt

NOTE: The above only works on a file, not when data is piped into ag.

If you want to check for lines not preceded by another line, e.g. you’re looking for…

name:
  anyOf:
    - ...

While avoiding:

name:
  type: object
  anyOf:
    - ...

Then use a negative lookbehind assertion:

rg --context 2 --pcre2 --regexp '(?<!type: object)anyOf:'

Ingore any matches with a lookahead

Imagine you have the following code across multiple files:

serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{
	AllowActiveLocked:  true,
	Client:             c.Globals.Client,
	Manifest:           c.manifest,
	Out:                out,
	ServiceVersionFlag: c.serviceVersion,
	VerboseMode:        c.Globals.Flag.Verbose,
})

You want to find every instance of the function call cmd.ServiceDetails but ignore any that have a ServiceNameFlag field set (which isn’t set in the above example).

To achieve this you’d use a negative lookahead (?!<pattern>). The following example uses the Vim ack plugin to search for the function call, then lookahead to make sure we don’t find the field, and then keep matching until the end of the function call…

:Ack! '(?s)cmd\.ServiceDetails\((?!.+?ServiceNameFlag).+?}\)'