summaryrefslogtreecommitdiff
path: root/src/pkg/strings/strings.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/strings/strings.go')
-rw-r--r--src/pkg/strings/strings.go104
1 files changed, 77 insertions, 27 deletions
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
index b6d84d07a..c192b1826 100644
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -328,49 +328,99 @@ func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
// TrimLeftFunc returns a slice of the string s with all leading
// Unicode code points c satisfying f(c) removed.
func TrimLeftFunc(s string, f func(r int) bool) string {
- start, end := 0, len(s)
- for start < end {
+ i := indexFunc(s, f, false)
+ if i == -1 {
+ return ""
+ }
+ return s[i:]
+}
+
+// TrimRightFunc returns a slice of the string s with all trailing
+// Unicode code points c satisfying f(c) removed.
+func TrimRightFunc(s string, f func(r int) bool) string {
+ i := lastIndexFunc(s, f, false)
+ if i >= 0 && s[i] >= utf8.RuneSelf {
+ _, wid := utf8.DecodeRuneInString(s[i:])
+ i += wid
+ } else {
+ i++
+ }
+ return s[0:i]
+}
+
+// TrimFunc returns a slice of the string s with all leading
+// and trailing Unicode code points c satisfying f(c) removed.
+func TrimFunc(s string, f func(r int) bool) string {
+ return TrimRightFunc(TrimLeftFunc(s, f), f)
+}
+
+// IndexFunc returns the index into s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s string, f func(r int) bool) int {
+ return indexFunc(s, f, true)
+}
+
+// LastIndexFunc returns the index into s of the last
+// Unicode code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s string, f func(r int) bool) int {
+ return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted. We could use IndexFunc directly, but this
+// way saves a closure allocation.
+func indexFunc(s string, f func(r int) bool, truth bool) int {
+ start := 0
+ for start < len(s) {
wid := 1
rune := int(s[start])
if rune >= utf8.RuneSelf {
- rune, wid = utf8.DecodeRuneInString(s[start:end])
+ rune, wid = utf8.DecodeRuneInString(s[start:])
}
- if !f(rune) {
- return s[start:]
+ if f(rune) == truth {
+ return start
}
start += wid
}
- return s[start:]
+ return -1
}
-// TrimRightFunc returns a slice of the string s with all trailing
-// Unicode code points c satisfying f(c) removed.
-func TrimRightFunc(s string, f func(r int) bool) string {
- start, end := 0, len(s)
- for start < end {
- wid := 1
- rune := int(s[end-wid])
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted. We could use IndexFunc directly, but this
+// way saves a closure allocation.
+func lastIndexFunc(s string, f func(r int) bool, truth bool) int {
+ end := len(s)
+ for end > 0 {
+ start := end - 1
+ rune := int(s[start])
if rune >= utf8.RuneSelf {
// Back up & look for beginning of rune. Mustn't pass start.
- for wid = 2; start <= end-wid && !utf8.RuneStart(s[end-wid]); wid++ {
+ for start--; start >= 0; start-- {
+ if utf8.RuneStart(s[start]) {
+ break
+ }
}
- if start > end-wid { // invalid UTF-8 sequence; stop processing
- return s[start:end]
+ if start < 0 {
+ return -1
+ }
+ var wid int
+ rune, wid = utf8.DecodeRuneInString(s[start:end])
+
+ // If we've decoded fewer bytes than we expected,
+ // we've got some invalid UTF-8, so make sure we return
+ // the last possible index in s.
+ if start+wid < end && f(utf8.RuneError) == truth {
+ return end - 1
}
- rune, wid = utf8.DecodeRuneInString(s[end-wid : end])
}
- if !f(rune) {
- return s[0:end]
+ if f(rune) == truth {
+ return start
}
- end -= wid
+ end = start
}
- return s[0:end]
-}
-
-// TrimFunc returns a slice of the string s with all leading
-// and trailing Unicode code points c satisfying f(c) removed.
-func TrimFunc(s string, f func(r int) bool) string {
- return TrimRightFunc(TrimLeftFunc(s, f), f)
+ return -1
}
func makeCutsetFunc(cutset string) func(rune int) bool {