]> Cypherpunks repositories - gostls13.git/commitdiff
regexp: add (*Regexp).SubexpIndex
authorSylvain Zimmer <sylvain@sylvainzimmer.com>
Mon, 29 Jul 2019 01:15:36 +0000 (03:15 +0200)
committerDaniel Martí <mvdan@mvdan.cc>
Fri, 10 Apr 2020 09:38:07 +0000 (09:38 +0000)
SubexpIndex returns the index of the first subexpression with the given name,
or -1 if there is no subexpression with that name.

Fixes #32420

Change-Id: Ie1f9d22d50fb84e18added80a9d9a9f6dca8ffc4
Reviewed-on: https://go-review.googlesource.com/c/go/+/187919
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
src/regexp/all_test.go
src/regexp/example_test.go
src/regexp/regexp.go

index 626a69142f5925825c983e108a4e46eecfe54938..be7a2e7111876de6d6f7f6be2514556a587bfa87 100644 (file)
@@ -418,24 +418,32 @@ func TestLiteralPrefix(t *testing.T) {
        }
 }
 
+type subexpIndex struct {
+       name  string
+       index int
+}
+
 type subexpCase struct {
-       input string
-       num   int
-       names []string
+       input   string
+       num     int
+       names   []string
+       indices []subexpIndex
 }
 
+var emptySubexpIndices = []subexpIndex{{"", -1}, {"missing", -1}}
+
 var subexpCases = []subexpCase{
-       {``, 0, nil},
-       {`.*`, 0, nil},
-       {`abba`, 0, nil},
-       {`ab(b)a`, 1, []string{"", ""}},
-       {`ab(.*)a`, 1, []string{"", ""}},
-       {`(.*)ab(.*)a`, 2, []string{"", "", ""}},
-       {`(.*)(ab)(.*)a`, 3, []string{"", "", "", ""}},
-       {`(.*)((a)b)(.*)a`, 4, []string{"", "", "", "", ""}},
-       {`(.*)(\(ab)(.*)a`, 3, []string{"", "", "", ""}},
-       {`(.*)(\(a\)b)(.*)a`, 3, []string{"", "", "", ""}},
-       {`(?P<foo>.*)(?P<bar>(a)b)(?P<foo>.*)a`, 4, []string{"", "foo", "bar", "", "foo"}},
+       {``, 0, nil, emptySubexpIndices},
+       {`.*`, 0, nil, emptySubexpIndices},
+       {`abba`, 0, nil, emptySubexpIndices},
+       {`ab(b)a`, 1, []string{"", ""}, emptySubexpIndices},
+       {`ab(.*)a`, 1, []string{"", ""}, emptySubexpIndices},
+       {`(.*)ab(.*)a`, 2, []string{"", "", ""}, emptySubexpIndices},
+       {`(.*)(ab)(.*)a`, 3, []string{"", "", "", ""}, emptySubexpIndices},
+       {`(.*)((a)b)(.*)a`, 4, []string{"", "", "", "", ""}, emptySubexpIndices},
+       {`(.*)(\(ab)(.*)a`, 3, []string{"", "", "", ""}, emptySubexpIndices},
+       {`(.*)(\(a\)b)(.*)a`, 3, []string{"", "", "", ""}, emptySubexpIndices},
+       {`(?P<foo>.*)(?P<bar>(a)b)(?P<foo>.*)a`, 4, []string{"", "foo", "bar", "", "foo"}, []subexpIndex{{"", -1}, {"missing", -1}, {"foo", 1}, {"bar", 2}}},
 }
 
 func TestSubexp(t *testing.T) {
@@ -458,6 +466,12 @@ func TestSubexp(t *testing.T) {
                                }
                        }
                }
+               for _, subexp := range c.indices {
+                       index := re.SubexpIndex(subexp.name)
+                       if index != subexp.index {
+                               t.Errorf("%q: SubexpIndex(%q) = %d, want %d", c.input, subexp.name, index, subexp.index)
+                       }
+               }
        }
 }
 
index ea35a2e5918e32256e9176263b3ed039fbc40f5b..466b38b0fa2aa48e8ca3d59c3d554f1d22e3f1bc 100644 (file)
@@ -280,6 +280,19 @@ func ExampleRegexp_SubexpNames() {
        // Turing Alan
 }
 
+func ExampleRegexp_SubexpIndex() {
+       re := regexp.MustCompile(`(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)`)
+       fmt.Println(re.MatchString("Alan Turing"))
+       matches := re.FindStringSubmatch("Alan Turing")
+       lastIndex := re.SubexpIndex("last")
+       fmt.Printf("last => %d\n", lastIndex)
+       fmt.Println(matches[lastIndex])
+       // Output:
+       // true
+       // last => 2
+       // Turing
+}
+
 func ExampleRegexp_Split() {
        a := regexp.MustCompile(`a`)
        fmt.Println(a.Split("banana", -1))
index 19ca6f2223f77cf018b9ddd447dfec537a28e42c..b547a2ab97d71a8e26f427942d307d39ddfb28b6 100644 (file)
@@ -345,6 +345,24 @@ func (re *Regexp) SubexpNames() []string {
        return re.subexpNames
 }
 
+// SubexpIndex returns the index of the first subexpression with the given name,
+// or -1 if there is no subexpression with that name.
+//
+// Note that multiple subexpressions can be written using the same name, as in
+// (?P<bob>a+)(?P<bob>b+), which declares two subexpressions named "bob".
+// In this case, SubexpIndex returns the index of the leftmost such subexpression
+// in the regular expression.
+func (re *Regexp) SubexpIndex(name string) int {
+       if name != "" {
+               for i, s := range re.subexpNames {
+                       if name == s {
+                               return i
+                       }
+               }
+       }
+       return -1
+}
+
 const endOfText rune = -1
 
 // input abstracts different representations of the input text. It provides