Sublime Forum

How to use back reference in replacement?

#1

i want to do some replacement with back reference,
such as the following code sample in my python file:

……
ff=self.view.find_all("\s*(\w+)\s*")
ff.reverse()
for rr in ff:
      self.view.replace(edit, rr, "\1")

but the back reference seems not working.
how should i do?
thx!

0 Likes

#2

It doesn’t work like that.

view.find_all returns a list of Regions and does not care about capturing groups. It returns the start and end coordinates of the match.

You will have to use python’s re.sub instead and extract the whole text before, do the replacement in your plugin and set the whole text back again. I actually remember answering this question a few ages ago, so maybe you will get more information by searching because I can’t bother to write a code example currently, sorry.

0 Likes

#3

You don’t have to replace the entire buffer, but you do have to search it. I did a plugin, RegReplace, where you can specify custom searches you can string together, and like FichteFoll mentioned, I had to use re on the view’s buffer. I basically wrote a function that would search the buffer and return the regions and the extractions (modified text after replace); like the Sublime API does. Then I could just iterate backwards through my sublime regions, tracking the index so I could access the corresponding extractions, and replace backwards. I don’t know if you lose all of your selections when you replace the entire buffer…I didn’t want to lose my selections, so I opted for replacing the regions in reverse order.

[pre=#232628] def regex_findall(self, find, flags, replace, extractions, literal=False, sel=None):
regions = ]
offset = 0
if sel is not None:
offset = sel.begin()
bfr = self.view.substr(sublime.Region(offset, sel.end()))
else:
bfr = self.view.substr(sublime.Region(0, self.view.size()))
flags |= re.MULTILINE
if literal:
find = re.escape(find)
for m in re.compile(find, flags).finditer(bfr):
regions.append(sublime.Region(offset + m.start(0), offset + m.end(0)))
extractions.append(m.expand(replace))
return regions[/pre]

replace corresponds to extractions (I’m cutting out unrelated code here):
[pre=#232628] def greedy_replace(self, find, replace, regions, scope_filter):
# Initialize replace

    count = len(regions) - 1

    for region in reversed(regions):

            replaced += 1

                self.view.replace(self.edit, region, replacecount])
        count -= 1
    return replaced[/pre]

Anyways, just showing a way to approach it.

0 Likes

#4

Maybee I’m oversimplifying things, but since sublime text already does the find for you, all you have to do is loop over the selections and use regex to replace the text:

[view.replace(edit, region, re.sub(pattern, r'\1', view.substr(region))) for region in reversed(list(view.find_all(pattern)))]

for clarification, this should do the same:

    pattern = 'value="(.*?)"'
    for region in reversed(list(view.find_all(pattern))):
        current_text = view.substr(region)
        new_text = re.sub(pattern, r'\1', current_text)
        view.replace(edit, region, new_text) 

re.sub() will only replace text where pattern applies and returns the original string otherwise

0 Likes

#5

great thanks to you all!

0 Likes

#6

[quote=“duy”]Maybee I’m oversimplifying things, but since sublime text already does the find for you, all you have to do is loop over the selections and use regex to replace the text:

[view.replace(edit, region, re.sub(pattern, r'\1', view.substr(region))) for region in reversed(list(view.find_all(pattern)))]

for clarification, this should do the same:

    pattern = 'value="(.*?)"'
    for region in reversed(list(view.find_all(pattern))):
        current_text = view.substr(region)
        new_text = re.sub(pattern, r'\1', current_text)
        view.replace(edit, region, new_text) 

re.sub() will only replace text where pattern applies and returns the original string otherwise[/quote]

It all depends on what you are doing. The example above requires you to search the same text multiple times. That isn’t necessarily a problem, but I don’t think it is necessary. Also, depending on how your original search is defined, you may have to modify it for the secondary search. Let’s say you are using lookaheads or lookbehinds, the return won’t include the non-capturing lookaheads and lookbehinds. When you do the subsearch the original regex will no longer be valid for your return text.

0 Likes