How can I find where one word is close to another word?

26 views
Skip to first unread message

Adrian Keister

unread,
Jul 25, 2020, 6:59:54 PM7/25/20
to vim_use

As most people on this forum are likely aware, searching for a word is straight-forward enough. If I want to find occurrences of the word 'arc', I can type / arc , with spaces around the three letters, to find basic occurrences of the word (ignoring punctuation). But suppose I want to find where two words are close together, say, within ten words? Here's an example:

Now is the time for all good men to come to the aid of their country.

In this test, I want to find all occurrences where the word 'aid' is within ten words of the word 'country'. How can I do that in Vim?


This is cross-posted on Vi and Vim Beta.


Thanks!

Tim Chase

unread,
Jul 25, 2020, 7:42:37 PM7/25/20
to Adrian Keister, vim...@googlegroups.com
On 2020-07-25 15:59, Adrian Keister wrote:
> Now is the time for all good men to come to the aid of their
> country.
>
> In this test, I want to find all occurrences where the word 'aid'
> is within ten words of the word 'country'. How can I do that in Vim?

It's way ugly and requires using the old regex engine[1] (asserted by
the "\%#=1" in the following pattern) to work, but this should do the
trick and be fairly DRY (only requires putting in each term once):

\%#=1\%(\S\+\_s\+\)\{,9}\<aid\>\&\%(\S\+\_s\+\)\{,9}\<country\>

I might have a fenceposting issue where "9" should be "8" or "10",
but it should give you the foundation to mess around. Also, I added
the "\<" and "\>" to anchor the words so you don't find things like
"I said my uncle is a country boy" (finding the "aid" in "said").
Again, season to taste for your own needs.

The cursor lands a little weirdly (especially noticable if you have
syntax highlighting turned on) because it starts from the point at
which "within the next N words you'll find "aid" and within the next N
words you'll also find "country".

Alternatively, if you don't mind typing your literals more than once,
you can do

/\<aid\>\%(\_s\+\S\+\)\{,10}\_s\+\<country\>\|\<country\>\%(\_s\+\S\+\)\{,10}\_s\+\<aid\>

which will highlight a little more neatly at the cost of extra typing.
However, it also doesn't scale as well if you have more than 2 words
because you need to provide every possible ordering. The method at
the top scales easily for however many words you want within an
N-word range.

Hopefully one or the other works well for you.

-tim


[1] For the record, the new regex engine gives me an

E363: pattern uses more memory than 'maxmempattern'

where the old engine works fine.




Adrian Keister

unread,
Jul 25, 2020, 8:54:14 PM7/25/20
to vim_use
Tim,

Many thanks!

There's an answer on the Stack Exchange site. Does that method work also?

Cheers.

Tim Chase

unread,
Jul 25, 2020, 9:41:55 PM7/25/20
to vim...@googlegroups.com
On 2020-07-25 17:54, Adrian Keister wrote:
> There's an answer on the Stack Exchange site. Does that method work
> also?

That method finds only the case in which you have "aid" *followed by*
"country", so if you have

"This country needs all good men to come to her aid."

it won't find that even though "country" and "aid" are within 10
words of each other.

You might recognize that it's pretty similar to the first half of my
2nd answer: "term1(N optional words)term2" which I then swap around
with "or term2(N optional words)term1".

So if you only need "X with Y following it within N words", that's
an easy solution. If you need to allow for arbitrary ordering of the
words, you need a bit more such as either of my suggestions.

-tim



Lifepillar

unread,
Jul 26, 2020, 4:30:12 AM7/26/20
to vim...@googlegroups.com
Another idea, based on \%V (see `:help %V`):

1. Search for some text, e.g.:

/country<Enter>

2. Move back the desired amount, e.g., 10 WORDS:

10B

3. Visually select the range to be searched, e.g. 20 WORDS:

v20W

4. Return to Normal mode and search within the previously selected range:

<Esc>/\%Vaid

5. To search for the next match, move forward (10W) and repeat.

Putting all that in a couple of macros, you could do:

qa/country<Enter>10Bv20W<Esc>/\%Vaid<Enter>q
qb10W@aq

Now you may type @b repeatedly to perform your search.

Hope this helps,
Life.

Adrian Keister

unread,
Jul 26, 2020, 10:34:58 AM7/26/20
to vim_use
Tim,

I haven't tried your code, yet, but I was wondering about this followup: 

Would it be possible to essentially parametrize your command in vimrc, so that I could do something like this?

/ps/firstword/secondword/distance

I'm using 'ps' for 'proximity search', but if that's already a taken command, we'd have to make it something else. 

Many thanks for your help!

Cheers,
Adrian
Reply all
Reply to author
Forward
0 new messages