]> Cypherpunks repositories - gostls13.git/commitdiff
strings: add LastIndexAny
authorBenny Siegert <bsiegert@gmail.com>
Fri, 12 Nov 2010 20:47:50 +0000 (12:47 -0800)
committerRob Pike <r@golang.org>
Fri, 12 Nov 2010 20:47:50 +0000 (12:47 -0800)
The need for a LastIndexAny function has come up in the discussion
for https://golang.org/cl/3008041/. This function is
implemented analogously to lastIndexFunc, using functions from
the utf8 package.

R=r, rsc, PeterGo
CC=golang-dev
https://golang.org/cl/3057041

src/pkg/bytes/bytes.go
src/pkg/bytes/bytes_test.go
src/pkg/strings/strings.go
src/pkg/strings/strings_test.go

index 1939fd567845484561decf3b5ba34781d346cf59..e26b29fb553ddb14f99eb8157ce483be92a858fe 100644 (file)
@@ -165,6 +165,25 @@ func IndexAny(s []byte, chars string) int {
        return -1
 }
 
+// LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
+// points.  It returns the byte index of the last occurrence in s of any of
+// the Unicode code points in chars.  It returns -1 if chars is empty or if
+// there is no code point in common.
+func LastIndexAny(s []byte, chars string) int {
+       if len(chars) > 0 {
+               for i := len(s); i > 0; {
+                       rune, size := utf8.DecodeLastRune(s[0:i])
+                       i -= size
+                       for _, m := range chars {
+                               if rune == m {
+                                       return i
+                               }
+                       }
+               }
+       }
+       return -1
+}
+
 // Generic split: splits after each instance of sep,
 // including sepSave bytes of sep in the subarrays.
 func genSplit(s, sep []byte, sepSave, n int) [][]byte {
index f3ca371f83e76f48b20b7d8f2474f004e89ba6c2..28e70865291e687598801872c142199220cac99b 100644 (file)
@@ -128,6 +128,20 @@ var indexAnyTests = []BinOpTest{
        {dots + dots + dots, " ", -1},
 }
 
+var lastIndexAnyTests = []BinOpTest{
+       {"", "", -1},
+       {"", "a", -1},
+       {"", "abc", -1},
+       {"a", "", -1},
+       {"a", "a", 0},
+       {"aaa", "a", 2},
+       {"abc", "xyz", -1},
+       {"abc", "ab", 1},
+       {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+       {"a.RegExp*", ".(|)*+?^$[]", 8},
+       {dots + dots + dots, " ", -1},
+}
+
 var indexRuneTests = []BinOpTest{
        {"", "a", -1},
        {"", "☺", -1},
@@ -150,18 +164,23 @@ func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, tes
        }
 }
 
-func TestIndex(t *testing.T)     { runIndexTests(t, Index, "Index", indexTests) }
-func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
-func TestIndexAny(t *testing.T) {
-       for _, test := range indexAnyTests {
+func runIndexAnyTests(t *testing.T, f func(s []byte, chars string) int, funcName string, testCases []BinOpTest) {
+       for _, test := range testCases {
                a := []byte(test.a)
-               actual := IndexAny(a, test.b)
+               actual := f(a, test.b)
                if actual != test.i {
-                       t.Errorf("IndexAny(%q,%q) = %v; want %v", a, test.b, actual, test.i)
+                       t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, test.b, actual, test.i)
                }
        }
 }
 
+func TestIndex(t *testing.T)     { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T)  { runIndexAnyTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) {
+       runIndexAnyTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests)
+}
+
 func TestIndexByte(t *testing.T) {
        for _, tt := range indexTests {
                if len(tt.b) != 1 {
index f08b855999e8b6039ffef5f2d29ca7092b778432..8bf86dadd0aa22b5324cc63c9f34878d368a8989 100644 (file)
@@ -142,6 +142,24 @@ func IndexAny(s, chars string) int {
        return -1
 }
 
+// LastIndexAny returns the index of the last instance of any Unicode code
+// point from chars in s, or -1 if no Unicode code point from chars is
+// present in s.
+func LastIndexAny(s, chars string) int {
+       if len(chars) > 0 {
+               for i := len(s); i > 0; {
+                       rune, size := utf8.DecodeLastRuneInString(s[0:i])
+                       i -= size
+                       for _, m := range chars {
+                               if rune == m {
+                                       return i
+                               }
+                       }
+               }
+       }
+       return -1
+}
+
 // Generic split: splits after each instance of sep,
 // including sepSave bytes of sep in the subarrays.
 func genSplit(s, sep string, sepSave, n int) []string {
index 657c8e89064242595740332ca8848337635fcd0e..734fdd33daa71f1ca90e5b6527c3a03ebb6120cf 100644 (file)
@@ -86,6 +86,19 @@ var indexAnyTests = []IndexTest{
        {"aRegExp*", ".(|)*+?^$[]", 7},
        {dots + dots + dots, " ", -1},
 }
+var lastIndexAnyTests = []IndexTest{
+       {"", "", -1},
+       {"", "a", -1},
+       {"", "abc", -1},
+       {"a", "", -1},
+       {"a", "a", 0},
+       {"aaa", "a", 2},
+       {"abc", "xyz", -1},
+       {"abc", "ab", 1},
+       {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+       {"a.RegExp*", ".(|)*+?^$[]", 8},
+       {dots + dots + dots, " ", -1},
+}
 
 // Execute f on each test case.  funcName should be the name of f; it's used
 // in failure reports.
@@ -98,9 +111,10 @@ func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, tes
        }
 }
 
-func TestIndex(t *testing.T)     { runIndexTests(t, Index, "Index", indexTests) }
-func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
-func TestIndexAny(t *testing.T)  { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestIndex(t *testing.T)        { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T)    { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T)     { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
 
 type ExplodeTest struct {
        s string