0

In a file with something like:

self.phrase
self.phrases
self.phrase.lower()
self.phrase_lowered
self.phrases[self.phrase]

I'd like to replace all self.phrase with self._phrase, except for self.phrases to get:

self._phrase
self.phrases
self._phrase.lower()
self._phrase_lowered
self.phrases[self._phrase]

Of the regexes I've tried, the first (and one I thought would work) was:

:%s/self\.phrase[^s]/self\._phrase\1/gc

But it didn't work.

Kache
  • 11,723
  • 10
  • 47
  • 71

3 Answers3

7

Using \> to mark the end of the word:

1,$s/self\.phrase\>/self._phrase/g
perreal
  • 85,397
  • 16
  • 134
  • 168
4

It is normally expressed by negative look-ahead rather then atom like [^s]:

%s/self\.phrases\@!/self._phrase/g

. With the help of \zs/\ze or look-behinds you can narrow down a number of characters to type:

%s/self\.\zs\zephrases\@!/_/g

%s/\v(self\.)@<=(phrases@!)@=/_/g

(though the latter is only 1 character less then the original).

ZyX
  • 49,123
  • 7
  • 101
  • 128
  • what's `\@!`? Does it have to do with not escaping the `.`? It looks like `\zs` and `\ze` denotes where to make the replacement. That last one barely looks like a regex. What's `\v()`, `@<=()`, and `@=`? – Kache Dec 12 '12 at 03:54
  • @Kache It is negative look-ahead, see `:h /\@!`. Dot is escaped because dot matches any character and not a dot. There is no `\v()`, there `\v` modifier changing vim to very-magic mode, `:h /\v`. `@=` is look-ahead, `:h /\@=` (backslash was ripped due to very-magic mode), `@<=` is look-behind (again, no parenthesis), `:h /\@<=`. Look-ahead means “match only if look-ahead matches following characters” (negative = not matches), look-behind is the same for the preceding characters. Applies to the atom. – ZyX Dec 12 '12 at 04:01
  • @Kache When reading regexes note that there are almost no things that apply to the following bracketed/bracered/… expression, almost everything applies to the preceding atom. Thus instead of asking about `\v()`, `@<=()` you should have asked about `\v`, `()@<=`[, `()@=`]. There are also exactly no things that apply to parenthesized regex and not to an atom. There are some exceptions for the first rule, but they are considered to be special form of brackets/braces/… with special meaning, not modifier. – ZyX Dec 12 '12 at 04:07
1

To get your backreference working, use capture groups:

:%s/self\.phrase\([^s]\)/self\._phrase\1/gc

However, as @gits points out, this does not solve your problem. I personally would recommend using @perreal's answer. It's more flexible and therefore more likely to work in the future. But if you're determined to something like the above, then the following will work:

%s/self\.phrase\([^s]\|\s*$\)/self\._phrase\1/gc
Tim Pote
  • 24,528
  • 6
  • 58
  • 63
  • Hold on, this doesn't work. `phrase[^s]` requires "phrase" to be followed by something that is not "s". This fails on the first line of your file. – glts Dec 12 '12 at 10:36
  • 1
    @gits So this is now a bit awkward. The question as it originally stood was ambiguous at best. The need to exclude `self.phrases` was not explicitly stated. So I simply told the OP how to get their backreference to show up (like the title says). But you're right. This is now clearly an *incorrect* answer and the solution I would use is @perreal's. The OP should probably mark @perreal's as correct. At any rate, I'll make this (crappy) solution work. See my edits. – Tim Pote Dec 12 '12 at 13:35