Merge "strutil: ContainsFold"

This commit is contained in:
Brad Fitzpatrick 2014-01-11 01:06:51 +00:00 committed by Gerrit Code Review
commit db24eb032f
2 changed files with 69 additions and 4 deletions

View File

@ -17,7 +17,11 @@ limitations under the License.
// Package strutil contains string and byte processing functions.
package strutil
import "strings"
import (
"strings"
"unicode"
"unicode/utf8"
)
// Fork of Go's implementation in pkg/strings/strings.go:
// Generic split: splits after each instance of sep,
@ -75,8 +79,28 @@ func HasSuffixFold(s, suffix string) bool {
return strings.EqualFold(s[len(s)-len(suffix):], suffix)
}
// ContainsFold is like strings.Contains but (ought to) use Unicode case-folding.
// ContainsFold is like strings.Contains but uses Unicode case-folding.
func ContainsFold(s, substr string) bool {
// TODO: Make this not do allocations.
return strings.Contains(strings.ToLower(s), strings.ToLower(substr))
if substr == "" {
return true
}
if s == "" {
return false
}
firstRune := rune(substr[0])
if firstRune >= utf8.RuneSelf {
firstRune, _ = utf8.DecodeRuneInString(substr)
}
firstLowerRune := unicode.SimpleFold(firstRune)
for i, rune := range s {
if len(s)-i < len(substr) {
return false
}
if rune == firstLowerRune || unicode.SimpleFold(rune) == firstLowerRune {
if HasPrefixFold(s[i:], substr) {
return true
}
}
}
return false
}

View File

@ -95,3 +95,44 @@ func TestHasSuffixFold(t *testing.T) {
}
}
}
func TestContainsFold(t *testing.T) {
// TODO: more tests, more languages.
// The k,K,Kelvin (for now failing) example once TODO in HasPrefixFold is fixed.
tests := []struct {
s, substr string
result bool
}{
{"camli", "CAML", true},
{"CAMLI", "caml", true},
{"cam", "Cam", true},
{"мир", "ми", true},
{"МИP", "ми", true},
{"КАМЛИЙСТОР", "камлийс", true},
{"КаМлИйСтОр", "КаМлИйС", true},
{"camli", "car", false},
{"caml", "camli", false},
{"camli", "AMLI", true},
{"CAMLI", "amli", true},
{"mli", "MLI", true},
{"мир", "ир", true},
{"МИP", "ми", true},
{"КАМЛИЙСТОР", "лийстор", true},
{"КаМлИйСтОр", "лИйСтОр", true},
{"мир", "р", true},
{"camli", "ali", false},
{"amli", "camli", false},
{"МИP", "и", true},
{"мир", "и", true},
{"КАМЛИЙСТОР", "лийс", true},
{"КаМлИйСтОр", "лИйС", true},
}
for _, tt := range tests {
r := ContainsFold(tt.s, tt.substr)
if r != tt.result {
t.Errorf("ContainsFold(%q, %q) returned %v", tt.s, tt.substr, r)
}
}
}