43

I want to search a string which starts with "abc" and ends with "xyz" in vim.

Below are the commands I've tried:

:1,$g/abc[\w\W]*xyz/
:1,$g/abc\[\\w\\W\]\*xyz/
:1,$g/abc*xyz/

"[\w\W]*" means the texts between "abc" and "xyz" can be any characters

"1,$" means the search range is from the 1st line to the last line in the file opened by vim.

I found that the search pattern

abc[\w\W]*xyz 

works in https://regex101.com/

why does it fail in vim?

Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286
Brian
  • 12,145
  • 20
  • 90
  • 153
  • 4
    use dot instead of [\w\W] – Avinash Raj Jun 22 '15 at 08:38
  • 3
    There are some difference between Vim's regex and PCRE used by [regex101](http://regex101.com). For more detail you can read this [question](https://stackoverflow.com/questions/3864467/whats-the-difference-between-vim-regex-and-normal-regex). However, I am not sure if `[\w\W]` is one of them. – SSC Jun 22 '15 at 08:56
  • 4
    Vim does support *some* character classes inside collections, but only a limited subset (for instance `[[:alpha:]]` works, but `[\w]` does not). You can see `:help /[]` for the supported character classes. – Marth Jun 22 '15 at 09:04
  • 1
    You may want to add `set incsearch` to your .vimrc. This will allow you to construct regular expressions and see the matches as you type them (using `/`, not `:global`). This helps me build more complicated regular expressions since you know where you go wrong instantly instead of having to type out the whole thing and then guess. – W. B. Reed Jun 22 '15 at 17:20

4 Answers4

51

The command below should work unless "any character" means something different for you than for Vim:

:g/abc.*xyz
  • . means "any character except an EOL".
  • * means "any number (including 0) of the previous atom".
  • 1,$ could be shortened to %.
  • :global works on the whole buffer by default so you don't even need the %.
  • The closing / is not needed if you don't follow :g/pattern by a command as in :g/foo/d.
romainl
  • 186,200
  • 21
  • 280
  • 313
  • why are we using `:global` here. just out of curiosity. Just using the search `/abc.*xyz` works. plus, if the user has `incsearch` set, they can see their search as they type it using `/`, but not using `:global`. Just to clarify, there's nothing _wrong_ with using `:global`, just seems odd to me. – W. B. Reed Jun 22 '15 at 17:18
  • 1
    @W.B.Reed, I use `:global` because that's the example given by the OP. Note that `:global` and `/` have vastly different purposes: `/` and `:global` are not interchangeable at all. – romainl Jun 22 '15 at 19:20
  • 1
    Oh agreed. It just seemed that the OP was asking to search for a string. As such, `/` seems more appropriate. If they just wanted to search for a string, then `/regex` seems more appropriate than `:g/regex`. `:g` is more appropriate when you want to _do_ something with those matches. – W. B. Reed Jun 22 '15 at 19:47
8

Once the file gets too large (say, 1GB), ":g/abc.*xyz" becomes quite slow.

I found that

cat fileName | grep abc | grep xyz >> searchResult.txt

is more efficient than using the search function in vim.

I know that this method may return lines that start with "xyz" and end with "abc".

But since this is a rare case in my file(and maybe this doesn't happen quite often for other people), I think I should write this method here.

Brian
  • 12,145
  • 20
  • 90
  • 153
  • 1
    I use this approach too, often with long log files. You can then pipe the output (of either of the two greps) to sed to select only the "abc.*xyz" cases – P2000 Mar 23 '20 at 05:41
1

It seems that inside the collection syntax [..], character classes such as \w can't be used, probably because it tests via character-by-character strategy. From :h /[]:

Matching with a collection can be slow, because each character in the text has to be compared with each character in the collection. Use one of the other atoms above when possible. Example: "\d" is much faster than "[0-9]" and matches the same characters.

You can, however, use similar functionalities specifically prepared for [..] syntax. From :h /[] again :

A character class expression is evaluated to the set of characters belonging to that character class.

examples include:

[:alnum:]     letters and digits                   
[:alpha:]     letters                              
[:blank:]     space and tab characters             
[:cntrl:]     control characters                   
[:digit:]     decimal digits                       
[:graph:]     printable characters excluding space 
[:lower:]     lowercase letters
Community
  • 1
  • 1
Yosh
  • 2,512
  • 3
  • 24
  • 30
0

If you want to find them one by one you can hit

/

and then write

abc.*xyz

and hit enter to find the first occurrence of the pattern. Then use n for the next occurrence and Shift + n for the previous one. This is how I usually do, since for me this is easier to modify those lines.

mcvkr
  • 3,209
  • 6
  • 38
  • 63