16

:s/pattern/replacement operates on the first match and :s/pattern/replacement/g on all.

How to operate only on the last one?

3 Answers 3

18

I would use \zs

:%s/.*\zspattern/replacement/

A little bit of explanation:

  • . represents any single character
  • * represents greedy matching (as many as possible)

In Vim you can use zero-width anchors \zs and \ze to define the start and the end of the searched pattern, which you wish to match. Anything before \zs and after \ze in your pattern will remain unaffected by replacement.

To make it easy to understand, I would like to use this example from wikia's Search and replace:

Save typing by using \zs and \ze to set the start and end of a pattern. For example, instead of:

:s/Copyright 2007 All Rights Reserved/Copyright 2008 All Rights Reserved/ 

Use:

:s/Copyright \zs2007\ze All Rights Reserved/2008/

For more information, look at

2
  • Can you please provide a basic description of what \zs does in your answer? Oct 13, 2015 at 17:59
  • 3
    It's worth noting that the reason this works is because .* is greedy.
    – Wildcard
    Mar 25, 2016 at 0:24
7

You can search for the last match by grouping all, \(.*\), but last ocurrence of pattern. Then exiting with the captured group, \1, and adding the replacement.

:%s/\(.*\)pattern/\1replacement/
1
  • (This is inferior to @ryuichiro's \zs solution, in that your \1 approach is functionally equivalent, but more verbose. (On the other hand, it may be easier to remember for some, particularly if they are used to other regex flavors.)) Dec 30, 2016 at 1:44
0

For the sake of completeness I thought I'd post an alternative. Vim has multi-items some of which are similar to the more standard regular expression lookaround assertions (negative/positive lookahead/lookbehind). https://stackoverflow.com/questions/2973436/regex-lookahead-lookbehind-and-atomic-groups

In this case we want a negative lookahead, \@!, meaning we want to assert that the atom that precedes the item does not occur after pattern. In this case the atom is the pattern itself preceded by anything else:

:%s/pattern\(.*pattern\)\@!/replacement/

The part inside the parentheses is zero-width and not included in the match so is not replaced by the substitution.

:h \@! for more information or :h pattern-multi-items for the whole section containing other lookaround variations.

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.