Search code examples
regexvimultisnips

How exactly is this regex working in UltiSnips for Vim?


I just started using UltiSnips for Vim and now I'm trying out transformations. I can't wrap my head around one of the first examples given in the screencast. The transformation is for an HTML tag to drop everything but the tag name for the closing tag. The relevant part of the snippet is given below

<$1>
</${1/(\w+).*/$1/}>

No matter how I look at it, what I get from this regex is that it is saying "Match a full word, and then all the characters after that. I tried it out using RegExr, and my assumption was correct. If given a text "div class=" the above regex matches the entire text.

I tried it out on python as well (since Ultisnips uses the python re module).

a = re.search('(\w+).*/$1/)

will give me the entire string in a.group(). It will also give me (0,10) as the answer for a.span(). Yet UltiSnips takes $1 to be just div.

Am I thinking about this the wrong way? How exactly is this working?

After trying the regex out on regex101.com, I get div as match group #1. I also get div as the only match if I use (\w+) instead of (\w+).*. But when I try to use

</${1/(\w+)/$1/}>

as the transformation syntax, the entire string that I type in (div class=) gets included. Basically it matches the whole string.


Solution

  • ${1/(\w+).*/$1/} replaces the string matched by (\w+).* (that is div class=), by $1.

    $1 is what is matched between (the first set of) parentheses. The expression between parentheses is \w+, which matches div. It doesn't match the entire div class= because of the space.

    Thus ${1/(\w+).*/$1/} replaces div class= by div. Which is exactly what it's supposed to happen.

    From Python:

    import re
    a = re.search('(\w+).*', 'div class=')
    print a.group(0, 1)
    

    Output:

    ('div class=', 'div')
    

    Namely, $0 is the entire string matched, div class=, and $1 is div.