0

I am using this working regex
:%s/\( to\)\([a-z]\)/\1 \2/c
to replace tothem with to them and tohim with to him.
But I do not want to look at words like together, tone, tonal, etc

I tried something like this
:%s/\(\?\!together|tone|tonal\)\( to\)\([a-z]\)/\1 \2/c
but I clearly have the syntax wrong.

1
  • 1
    :h perl-patterns
    – Matt
    Feb 23, 2021 at 13:19

2 Answers 2

3

I think what you are trying to use with \?\! is an adaptation of Perl's zero with lookahead which doesn't exist in vim. The equivalent in vim is :h /\@!, you could use it this way:

:%s/\(to\)\(gether\|nal\|ne\)\@!\([a-z]\)/\1 \3

    \(to\)                                          match "to"
                             \@!                    not followed by
          \(gether\|nal\|ne\)                       "gether", "nal", "ne"
                                \([a-z]\)           and capture the next letter

However to me that doesn't look very efficient because you need to write the list of the valid values.

Maybe you could use set spell to highlight the wrong words, navigate to the matches with ]s and then run :s/\(to\)\([a-z]\)/\1 \2 (which you can repeat with @: if needed.

4
  • 1
    I use neovim and there's \zs and \ze that works as lookahead and behind. Is it not available on vim ? Feb 23, 2021 at 15:11
  • 1
    @JustKhaithang \zs and \ze also exists in vim it's just that here I'm not sure how to use them efficiently to achieve OP's goal. But if you have a solution using them don't hesitate to post an answer: The more diversity in the answer the more their is to learn for everybody :)
    – statox
    Feb 23, 2021 at 15:16
  • @Satox, ideally what I would do is use a dictionary file, lots of words to ignore, and the :h /\@! syntax. Using set spell wasn't really an option becasue of the size of the file, but a very good idea
    – Kes
    Mar 1, 2021 at 16:11
  • 1
    @Kes Depending on the size of the dictionary maybe you could built the regex via vimscript: Reading the dictionary, concatenating it into a string \(word1\|word2\|word3\) and then running the substitution but I'm not sure about the performances. To do it maybe sed + a shell script would be easier to use.
    – statox
    Mar 1, 2021 at 16:26
3

If those two (tothem and tohim) are the only patterns then you can modify the regexp to be more specific i.e. to only match those two specific patterns :

:%s/\( to\)\(him\|them\)/\1 \2/c

Another way :

:%s/\( to\)\(.\?..m\)/\1 \2/c

The regex in the second group is looking for a pattern that has either 2 or 3 character followed by the character m.

The more the merrier :

:%s/\( to\)\(.\?h[ie]m\)/\1 \2/c 
1
  • thank you :) That is a nice way of doing it. For this case there were so many different joined words in a large file that a dictionary would, I think, have been necessary.
    – Kes
    Mar 1, 2021 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.