Commit d0ffee8a authored by Robert Griesemer's avatar Robert Griesemer

bytes, strings: IndexOfAny

+ first use in go/doc

R=r
CC=golang-dev
https://golang.org/cl/781041
parent 9e481e29
...@@ -125,6 +125,21 @@ func LastIndex(s, sep []byte) int { ...@@ -125,6 +125,21 @@ func LastIndex(s, sep []byte) int {
return -1 return -1
} }
// IndexAny returns the index of the first instance of any byte
// from bytes in s, or -1 if no byte from bytes is present in s.
func IndexAny(s, bytes []byte) int {
if len(bytes) > 0 {
for i, b := range s {
for _, m := range bytes {
if b == m {
return i
}
}
}
}
return -1
}
// Generic split: splits after each instance of sep, // Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays. // including sepSave bytes of sep in the subarrays.
func genSplit(s, sep []byte, sepSave, n int) [][]byte { func genSplit(s, sep []byte, sepSave, n int) [][]byte {
......
...@@ -72,16 +72,19 @@ func TestCompare(t *testing.T) { ...@@ -72,16 +72,19 @@ func TestCompare(t *testing.T) {
} }
} }
var indextests = []BinOpTest{ var indexTests = []BinOpTest{
BinOpTest{"", "", 0}, BinOpTest{"", "", 0},
BinOpTest{"a", "", 0},
BinOpTest{"", "a", -1}, BinOpTest{"", "a", -1},
BinOpTest{"abc", "abc", 0}, BinOpTest{"", "foo", -1},
BinOpTest{"ab", "abc", -1}, BinOpTest{"fo", "foo", -1},
BinOpTest{"abc", "bc", 1}, BinOpTest{"foo", "foo", 0},
BinOpTest{"x", "ab", -1}, BinOpTest{"oofofoofooo", "f", 2},
// one-byte tests for IndexByte BinOpTest{"oofofoofooo", "foo", 4},
BinOpTest{"ab", "x", -1}, BinOpTest{"barfoobarfoo", "foo", 3},
BinOpTest{"foo", "", 0},
BinOpTest{"foo", "o", 1},
BinOpTest{"abcABCabc", "A", 3},
// cases with one byte strings - test IndexByte and special case in Index()
BinOpTest{"", "a", -1}, BinOpTest{"", "a", -1},
BinOpTest{"x", "a", -1}, BinOpTest{"x", "a", -1},
BinOpTest{"x", "x", 0}, BinOpTest{"x", "x", 0},
...@@ -91,19 +94,54 @@ var indextests = []BinOpTest{ ...@@ -91,19 +94,54 @@ var indextests = []BinOpTest{
BinOpTest{"abc", "x", -1}, BinOpTest{"abc", "x", -1},
} }
func TestIndex(t *testing.T) { var lastIndexTests = []BinOpTest{
for _, tt := range indextests { BinOpTest{"", "", 0},
a := []byte(tt.a) BinOpTest{"", "a", -1},
b := []byte(tt.b) BinOpTest{"", "foo", -1},
pos := Index(a, b) BinOpTest{"fo", "foo", -1},
if pos != tt.i { BinOpTest{"foo", "foo", 0},
t.Errorf(`Index(%q, %q) = %v`, tt.a, tt.b, pos) BinOpTest{"foo", "f", 0},
BinOpTest{"oofofoofooo", "f", 7},
BinOpTest{"oofofoofooo", "foo", 7},
BinOpTest{"barfoobarfoo", "foo", 9},
BinOpTest{"foo", "", 3},
BinOpTest{"foo", "o", 2},
BinOpTest{"abcABCabc", "A", 3},
BinOpTest{"abcABCabc", "a", 6},
}
var indexAnyTests = []BinOpTest{
BinOpTest{"", "", -1},
BinOpTest{"", "a", -1},
BinOpTest{"", "abc", -1},
BinOpTest{"a", "", -1},
BinOpTest{"a", "a", 0},
BinOpTest{"aaa", "a", 0},
BinOpTest{"abc", "xyz", -1},
BinOpTest{"abc", "xcz", 2},
BinOpTest{"aRegExp*", ".(|)*+?^$[]", 7},
BinOpTest{dots + dots + dots, " ", -1},
}
// Execute f on each test case. funcName should be the name of f; it's used
// in failure reports.
func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, testCases []BinOpTest) {
for _, test := range testCases {
a := []byte(test.a)
b := []byte(test.b)
actual := f(a, b)
if actual != test.i {
t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, 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) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
func TestIndexByte(t *testing.T) { func TestIndexByte(t *testing.T) {
for _, tt := range indextests { for _, tt := range indexTests {
if len(tt.b) != 1 { if len(tt.b) != 1 {
continue continue
} }
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"go/ast" "go/ast"
"go/token" "go/token"
"regexp" "regexp"
"strings"
"sort" "sort"
) )
...@@ -564,15 +565,7 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc ...@@ -564,15 +565,7 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
// Does s look like a regular expression? // Does s look like a regular expression?
func isRegexp(s string) bool { func isRegexp(s string) bool {
metachars := ".(|)*+?^$[]" return strings.IndexAny(s, ".(|)*+?^$[]") >= 0
for _, c := range s {
for _, m := range metachars {
if c == m {
return true
}
}
}
return false
} }
......
...@@ -106,6 +106,21 @@ func LastIndex(s, sep string) int { ...@@ -106,6 +106,21 @@ func LastIndex(s, sep string) int {
return -1 return -1
} }
// IndexAny returns the index of the first instance of any Unicode code point
// from chars in s, or -1 if no Unicode code point from chars is present in s.
func IndexAny(s, chars string) int {
if len(chars) > 0 {
for i, c := range s {
for _, m := range chars {
if c == m {
return i
}
}
}
}
return -1
}
// Generic split: splits after each instance of sep, // Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays. // including sepSave bytes of sep in the subarrays.
func genSplit(s, sep string, sepSave, n int) []string { func genSplit(s, sep string, sepSave, n int) []string {
......
...@@ -72,6 +72,20 @@ var lastIndexTests = []IndexTest{ ...@@ -72,6 +72,20 @@ var lastIndexTests = []IndexTest{
IndexTest{"abcABCabc", "a", 6}, IndexTest{"abcABCabc", "a", 6},
} }
var indexAnyTests = []IndexTest{
IndexTest{"", "", -1},
IndexTest{"", "a", -1},
IndexTest{"", "abc", -1},
IndexTest{"a", "", -1},
IndexTest{"a", "a", 0},
IndexTest{"aaa", "a", 0},
IndexTest{"abc", "xyz", -1},
IndexTest{"abc", "xcz", 2},
IndexTest{"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
IndexTest{"aRegExp*", ".(|)*+?^$[]", 7},
IndexTest{dots + dots + dots, " ", -1},
}
// Execute f on each test case. funcName should be the name of f; it's used // Execute f on each test case. funcName should be the name of f; it's used
// in failure reports. // in failure reports.
func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) { func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) {
...@@ -83,10 +97,9 @@ func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, tes ...@@ -83,10 +97,9 @@ 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 TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) } func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
type ExplodeTest struct { type ExplodeTest struct {
s string s string
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment