f8d9fa9e80
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. From-SVN: r219627
763 lines
19 KiB
Go
763 lines
19 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package strings implements simple functions to manipulate strings.
|
|
package strings
|
|
|
|
import (
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit).
|
|
// Invalid UTF-8 sequences become correct encodings of U+FFF8.
|
|
func explode(s string, n int) []string {
|
|
if n == 0 {
|
|
return nil
|
|
}
|
|
l := utf8.RuneCountInString(s)
|
|
if n <= 0 || n > l {
|
|
n = l
|
|
}
|
|
a := make([]string, n)
|
|
var size int
|
|
var ch rune
|
|
i, cur := 0, 0
|
|
for ; i+1 < n; i++ {
|
|
ch, size = utf8.DecodeRuneInString(s[cur:])
|
|
if ch == utf8.RuneError {
|
|
a[i] = string(utf8.RuneError)
|
|
} else {
|
|
a[i] = s[cur : cur+size]
|
|
}
|
|
cur += size
|
|
}
|
|
// add the rest, if there is any
|
|
if cur < len(s) {
|
|
a[i] = s[cur:]
|
|
}
|
|
return a
|
|
}
|
|
|
|
// primeRK is the prime base used in Rabin-Karp algorithm.
|
|
const primeRK = 16777619
|
|
|
|
// hashStr returns the hash and the appropriate multiplicative
|
|
// factor for use in Rabin-Karp algorithm.
|
|
func hashStr(sep string) (uint32, uint32) {
|
|
hash := uint32(0)
|
|
for i := 0; i < len(sep); i++ {
|
|
hash = hash*primeRK + uint32(sep[i])
|
|
}
|
|
var pow, sq uint32 = 1, primeRK
|
|
for i := len(sep); i > 0; i >>= 1 {
|
|
if i&1 != 0 {
|
|
pow *= sq
|
|
}
|
|
sq *= sq
|
|
}
|
|
return hash, pow
|
|
}
|
|
|
|
// hashStrRev returns the hash of the reverse of sep and the
|
|
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
|
func hashStrRev(sep string) (uint32, uint32) {
|
|
hash := uint32(0)
|
|
for i := len(sep) - 1; i >= 0; i-- {
|
|
hash = hash*primeRK + uint32(sep[i])
|
|
}
|
|
var pow, sq uint32 = 1, primeRK
|
|
for i := len(sep); i > 0; i >>= 1 {
|
|
if i&1 != 0 {
|
|
pow *= sq
|
|
}
|
|
sq *= sq
|
|
}
|
|
return hash, pow
|
|
}
|
|
|
|
// Count counts the number of non-overlapping instances of sep in s.
|
|
func Count(s, sep string) int {
|
|
n := 0
|
|
// special cases
|
|
switch {
|
|
case len(sep) == 0:
|
|
return utf8.RuneCountInString(s) + 1
|
|
case len(sep) == 1:
|
|
// special case worth making fast
|
|
c := sep[0]
|
|
for i := 0; i < len(s); i++ {
|
|
if s[i] == c {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
case len(sep) > len(s):
|
|
return 0
|
|
case len(sep) == len(s):
|
|
if sep == s {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
// Rabin-Karp search
|
|
hashsep, pow := hashStr(sep)
|
|
h := uint32(0)
|
|
for i := 0; i < len(sep); i++ {
|
|
h = h*primeRK + uint32(s[i])
|
|
}
|
|
lastmatch := 0
|
|
if h == hashsep && s[:len(sep)] == sep {
|
|
n++
|
|
lastmatch = len(sep)
|
|
}
|
|
for i := len(sep); i < len(s); {
|
|
h *= primeRK
|
|
h += uint32(s[i])
|
|
h -= pow * uint32(s[i-len(sep)])
|
|
i++
|
|
if h == hashsep && lastmatch <= i-len(sep) && s[i-len(sep):i] == sep {
|
|
n++
|
|
lastmatch = i
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Contains returns true if substr is within s.
|
|
func Contains(s, substr string) bool {
|
|
return Index(s, substr) >= 0
|
|
}
|
|
|
|
// ContainsAny returns true if any Unicode code points in chars are within s.
|
|
func ContainsAny(s, chars string) bool {
|
|
return IndexAny(s, chars) >= 0
|
|
}
|
|
|
|
// ContainsRune returns true if the Unicode code point r is within s.
|
|
func ContainsRune(s string, r rune) bool {
|
|
return IndexRune(s, r) >= 0
|
|
}
|
|
|
|
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
|
|
func Index(s, sep string) int {
|
|
n := len(sep)
|
|
switch {
|
|
case n == 0:
|
|
return 0
|
|
case n == 1:
|
|
return IndexByte(s, sep[0])
|
|
case n == len(s):
|
|
if sep == s {
|
|
return 0
|
|
}
|
|
return -1
|
|
case n > len(s):
|
|
return -1
|
|
}
|
|
// Rabin-Karp search
|
|
hashsep, pow := hashStr(sep)
|
|
var h uint32
|
|
for i := 0; i < n; i++ {
|
|
h = h*primeRK + uint32(s[i])
|
|
}
|
|
if h == hashsep && s[:n] == sep {
|
|
return 0
|
|
}
|
|
for i := n; i < len(s); {
|
|
h *= primeRK
|
|
h += uint32(s[i])
|
|
h -= pow * uint32(s[i-n])
|
|
i++
|
|
if h == hashsep && s[i-n:i] == sep {
|
|
return i - n
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
|
|
func LastIndex(s, sep string) int {
|
|
n := len(sep)
|
|
switch {
|
|
case n == 0:
|
|
return len(s)
|
|
case n == 1:
|
|
// special case worth making fast
|
|
c := sep[0]
|
|
for i := len(s) - 1; i >= 0; i-- {
|
|
if s[i] == c {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
case n == len(s):
|
|
if sep == s {
|
|
return 0
|
|
}
|
|
return -1
|
|
case n > len(s):
|
|
return -1
|
|
}
|
|
// Rabin-Karp search from the end of the string
|
|
hashsep, pow := hashStrRev(sep)
|
|
last := len(s) - n
|
|
var h uint32
|
|
for i := len(s) - 1; i >= last; i-- {
|
|
h = h*primeRK + uint32(s[i])
|
|
}
|
|
if h == hashsep && s[last:] == sep {
|
|
return last
|
|
}
|
|
for i := last - 1; i >= 0; i-- {
|
|
h *= primeRK
|
|
h += uint32(s[i])
|
|
h -= pow * uint32(s[i+n])
|
|
if h == hashsep && s[i:i+n] == sep {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// IndexRune returns the index of the first instance of the Unicode code point
|
|
// r, or -1 if rune is not present in s.
|
|
func IndexRune(s string, r rune) int {
|
|
switch {
|
|
case r < utf8.RuneSelf:
|
|
return IndexByte(s, byte(r))
|
|
default:
|
|
for i, c := range s {
|
|
if c == r {
|
|
return i
|
|
}
|
|
}
|
|
}
|
|
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
|
|
}
|
|
|
|
// 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 {
|
|
if n == 0 {
|
|
return nil
|
|
}
|
|
if sep == "" {
|
|
return explode(s, n)
|
|
}
|
|
if n < 0 {
|
|
n = Count(s, sep) + 1
|
|
}
|
|
c := sep[0]
|
|
start := 0
|
|
a := make([]string, n)
|
|
na := 0
|
|
for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
|
|
if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
|
|
a[na] = s[start : i+sepSave]
|
|
na++
|
|
start = i + len(sep)
|
|
i += len(sep) - 1
|
|
}
|
|
}
|
|
a[na] = s[start:]
|
|
return a[0 : na+1]
|
|
}
|
|
|
|
// SplitN slices s into substrings separated by sep and returns a slice of
|
|
// the substrings between those separators.
|
|
// If sep is empty, SplitN splits after each UTF-8 sequence.
|
|
// The count determines the number of substrings to return:
|
|
// n > 0: at most n substrings; the last substring will be the unsplit remainder.
|
|
// n == 0: the result is nil (zero substrings)
|
|
// n < 0: all substrings
|
|
func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
|
|
|
|
// SplitAfterN slices s into substrings after each instance of sep and
|
|
// returns a slice of those substrings.
|
|
// If sep is empty, SplitAfterN splits after each UTF-8 sequence.
|
|
// The count determines the number of substrings to return:
|
|
// n > 0: at most n substrings; the last substring will be the unsplit remainder.
|
|
// n == 0: the result is nil (zero substrings)
|
|
// n < 0: all substrings
|
|
func SplitAfterN(s, sep string, n int) []string {
|
|
return genSplit(s, sep, len(sep), n)
|
|
}
|
|
|
|
// Split slices s into all substrings separated by sep and returns a slice of
|
|
// the substrings between those separators.
|
|
// If sep is empty, Split splits after each UTF-8 sequence.
|
|
// It is equivalent to SplitN with a count of -1.
|
|
func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
|
|
|
|
// SplitAfter slices s into all substrings after each instance of sep and
|
|
// returns a slice of those substrings.
|
|
// If sep is empty, SplitAfter splits after each UTF-8 sequence.
|
|
// It is equivalent to SplitAfterN with a count of -1.
|
|
func SplitAfter(s, sep string) []string {
|
|
return genSplit(s, sep, len(sep), -1)
|
|
}
|
|
|
|
// Fields splits the string s around each instance of one or more consecutive white space
|
|
// characters, as defined by unicode.IsSpace, returning an array of substrings of s or an
|
|
// empty list if s contains only white space.
|
|
func Fields(s string) []string {
|
|
return FieldsFunc(s, unicode.IsSpace)
|
|
}
|
|
|
|
// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
|
|
// and returns an array of slices of s. If all code points in s satisfy f(c) or the
|
|
// string is empty, an empty slice is returned.
|
|
// FieldsFunc makes no guarantees about the order in which it calls f(c).
|
|
// If f does not return consistent results for a given c, FieldsFunc may crash.
|
|
func FieldsFunc(s string, f func(rune) bool) []string {
|
|
// First count the fields.
|
|
n := 0
|
|
inField := false
|
|
for _, rune := range s {
|
|
wasInField := inField
|
|
inField = !f(rune)
|
|
if inField && !wasInField {
|
|
n++
|
|
}
|
|
}
|
|
|
|
// Now create them.
|
|
a := make([]string, n)
|
|
na := 0
|
|
fieldStart := -1 // Set to -1 when looking for start of field.
|
|
for i, rune := range s {
|
|
if f(rune) {
|
|
if fieldStart >= 0 {
|
|
a[na] = s[fieldStart:i]
|
|
na++
|
|
fieldStart = -1
|
|
}
|
|
} else if fieldStart == -1 {
|
|
fieldStart = i
|
|
}
|
|
}
|
|
if fieldStart >= 0 { // Last field might end at EOF.
|
|
a[na] = s[fieldStart:]
|
|
}
|
|
return a
|
|
}
|
|
|
|
// Join concatenates the elements of a to create a single string. The separator string
|
|
// sep is placed between elements in the resulting string.
|
|
func Join(a []string, sep string) string {
|
|
if len(a) == 0 {
|
|
return ""
|
|
}
|
|
if len(a) == 1 {
|
|
return a[0]
|
|
}
|
|
n := len(sep) * (len(a) - 1)
|
|
for i := 0; i < len(a); i++ {
|
|
n += len(a[i])
|
|
}
|
|
|
|
b := make([]byte, n)
|
|
bp := copy(b, a[0])
|
|
for _, s := range a[1:] {
|
|
bp += copy(b[bp:], sep)
|
|
bp += copy(b[bp:], s)
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// HasPrefix tests whether the string s begins with prefix.
|
|
func HasPrefix(s, prefix string) bool {
|
|
return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
|
|
}
|
|
|
|
// HasSuffix tests whether the string s ends with suffix.
|
|
func HasSuffix(s, suffix string) bool {
|
|
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
|
|
}
|
|
|
|
// Map returns a copy of the string s with all its characters modified
|
|
// according to the mapping function. If mapping returns a negative value, the character is
|
|
// dropped from the string with no replacement.
|
|
func Map(mapping func(rune) rune, s string) string {
|
|
// In the worst case, the string can grow when mapped, making
|
|
// things unpleasant. But it's so rare we barge in assuming it's
|
|
// fine. It could also shrink but that falls out naturally.
|
|
maxbytes := len(s) // length of b
|
|
nbytes := 0 // number of bytes encoded in b
|
|
// The output buffer b is initialized on demand, the first
|
|
// time a character differs.
|
|
var b []byte
|
|
|
|
for i, c := range s {
|
|
r := mapping(c)
|
|
if b == nil {
|
|
if r == c {
|
|
continue
|
|
}
|
|
b = make([]byte, maxbytes)
|
|
nbytes = copy(b, s[:i])
|
|
}
|
|
if r >= 0 {
|
|
wid := 1
|
|
if r >= utf8.RuneSelf {
|
|
wid = utf8.RuneLen(r)
|
|
}
|
|
if nbytes+wid > maxbytes {
|
|
// Grow the buffer.
|
|
maxbytes = maxbytes*2 + utf8.UTFMax
|
|
nb := make([]byte, maxbytes)
|
|
copy(nb, b[0:nbytes])
|
|
b = nb
|
|
}
|
|
nbytes += utf8.EncodeRune(b[nbytes:maxbytes], r)
|
|
}
|
|
}
|
|
if b == nil {
|
|
return s
|
|
}
|
|
return string(b[0:nbytes])
|
|
}
|
|
|
|
// Repeat returns a new string consisting of count copies of the string s.
|
|
func Repeat(s string, count int) string {
|
|
b := make([]byte, len(s)*count)
|
|
bp := copy(b, s)
|
|
for bp < len(b) {
|
|
copy(b[bp:], b[:bp])
|
|
bp *= 2
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
|
|
func ToUpper(s string) string { return Map(unicode.ToUpper, s) }
|
|
|
|
// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
|
|
func ToLower(s string) string { return Map(unicode.ToLower, s) }
|
|
|
|
// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
|
|
func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
|
|
|
|
// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
|
|
// upper case, giving priority to the special casing rules.
|
|
func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
|
|
return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
|
|
}
|
|
|
|
// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
|
|
// lower case, giving priority to the special casing rules.
|
|
func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
|
|
return Map(func(r rune) rune { return _case.ToLower(r) }, s)
|
|
}
|
|
|
|
// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
|
|
// title case, giving priority to the special casing rules.
|
|
func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
|
|
return Map(func(r rune) rune { return _case.ToTitle(r) }, s)
|
|
}
|
|
|
|
// isSeparator reports whether the rune could mark a word boundary.
|
|
// TODO: update when package unicode captures more of the properties.
|
|
func isSeparator(r rune) bool {
|
|
// ASCII alphanumerics and underscore are not separators
|
|
if r <= 0x7F {
|
|
switch {
|
|
case '0' <= r && r <= '9':
|
|
return false
|
|
case 'a' <= r && r <= 'z':
|
|
return false
|
|
case 'A' <= r && r <= 'Z':
|
|
return false
|
|
case r == '_':
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
// Letters and digits are not separators
|
|
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
|
return false
|
|
}
|
|
// Otherwise, all we can do for now is treat spaces as separators.
|
|
return unicode.IsSpace(r)
|
|
}
|
|
|
|
// Title returns a copy of the string s with all Unicode letters that begin words
|
|
// mapped to their title case.
|
|
//
|
|
// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
|
|
func Title(s string) string {
|
|
// Use a closure here to remember state.
|
|
// Hackish but effective. Depends on Map scanning in order and calling
|
|
// the closure once per rune.
|
|
prev := ' '
|
|
return Map(
|
|
func(r rune) rune {
|
|
if isSeparator(prev) {
|
|
prev = r
|
|
return unicode.ToTitle(r)
|
|
}
|
|
prev = r
|
|
return r
|
|
},
|
|
s)
|
|
}
|
|
|
|
// 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(rune) bool) string {
|
|
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(rune) 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(rune) 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(rune) 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(rune) 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.
|
|
func indexFunc(s string, f func(rune) bool, truth bool) int {
|
|
start := 0
|
|
for start < len(s) {
|
|
wid := 1
|
|
r := rune(s[start])
|
|
if r >= utf8.RuneSelf {
|
|
r, wid = utf8.DecodeRuneInString(s[start:])
|
|
}
|
|
if f(r) == truth {
|
|
return start
|
|
}
|
|
start += wid
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// lastIndexFunc is the same as LastIndexFunc except that if
|
|
// truth==false, the sense of the predicate function is
|
|
// inverted.
|
|
func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
|
|
for i := len(s); i > 0; {
|
|
r, size := utf8.DecodeLastRuneInString(s[0:i])
|
|
i -= size
|
|
if f(r) == truth {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func makeCutsetFunc(cutset string) func(rune) bool {
|
|
return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
|
|
}
|
|
|
|
// Trim returns a slice of the string s with all leading and
|
|
// trailing Unicode code points contained in cutset removed.
|
|
func Trim(s string, cutset string) string {
|
|
if s == "" || cutset == "" {
|
|
return s
|
|
}
|
|
return TrimFunc(s, makeCutsetFunc(cutset))
|
|
}
|
|
|
|
// TrimLeft returns a slice of the string s with all leading
|
|
// Unicode code points contained in cutset removed.
|
|
func TrimLeft(s string, cutset string) string {
|
|
if s == "" || cutset == "" {
|
|
return s
|
|
}
|
|
return TrimLeftFunc(s, makeCutsetFunc(cutset))
|
|
}
|
|
|
|
// TrimRight returns a slice of the string s, with all trailing
|
|
// Unicode code points contained in cutset removed.
|
|
func TrimRight(s string, cutset string) string {
|
|
if s == "" || cutset == "" {
|
|
return s
|
|
}
|
|
return TrimRightFunc(s, makeCutsetFunc(cutset))
|
|
}
|
|
|
|
// TrimSpace returns a slice of the string s, with all leading
|
|
// and trailing white space removed, as defined by Unicode.
|
|
func TrimSpace(s string) string {
|
|
return TrimFunc(s, unicode.IsSpace)
|
|
}
|
|
|
|
// TrimPrefix returns s without the provided leading prefix string.
|
|
// If s doesn't start with prefix, s is returned unchanged.
|
|
func TrimPrefix(s, prefix string) string {
|
|
if HasPrefix(s, prefix) {
|
|
return s[len(prefix):]
|
|
}
|
|
return s
|
|
}
|
|
|
|
// TrimSuffix returns s without the provided trailing suffix string.
|
|
// If s doesn't end with suffix, s is returned unchanged.
|
|
func TrimSuffix(s, suffix string) string {
|
|
if HasSuffix(s, suffix) {
|
|
return s[:len(s)-len(suffix)]
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Replace returns a copy of the string s with the first n
|
|
// non-overlapping instances of old replaced by new.
|
|
// If old is empty, it matches at the beginning of the string
|
|
// and after each UTF-8 sequence, yielding up to k+1 replacements
|
|
// for a k-rune string.
|
|
// If n < 0, there is no limit on the number of replacements.
|
|
func Replace(s, old, new string, n int) string {
|
|
if old == new || n == 0 {
|
|
return s // avoid allocation
|
|
}
|
|
|
|
// Compute number of replacements.
|
|
if m := Count(s, old); m == 0 {
|
|
return s // avoid allocation
|
|
} else if n < 0 || m < n {
|
|
n = m
|
|
}
|
|
|
|
// Apply replacements to buffer.
|
|
t := make([]byte, len(s)+n*(len(new)-len(old)))
|
|
w := 0
|
|
start := 0
|
|
for i := 0; i < n; i++ {
|
|
j := start
|
|
if len(old) == 0 {
|
|
if i > 0 {
|
|
_, wid := utf8.DecodeRuneInString(s[start:])
|
|
j += wid
|
|
}
|
|
} else {
|
|
j += Index(s[start:], old)
|
|
}
|
|
w += copy(t[w:], s[start:j])
|
|
w += copy(t[w:], new)
|
|
start = j + len(old)
|
|
}
|
|
w += copy(t[w:], s[start:])
|
|
return string(t[0:w])
|
|
}
|
|
|
|
// EqualFold reports whether s and t, interpreted as UTF-8 strings,
|
|
// are equal under Unicode case-folding.
|
|
func EqualFold(s, t string) bool {
|
|
for s != "" && t != "" {
|
|
// Extract first rune from each string.
|
|
var sr, tr rune
|
|
if s[0] < utf8.RuneSelf {
|
|
sr, s = rune(s[0]), s[1:]
|
|
} else {
|
|
r, size := utf8.DecodeRuneInString(s)
|
|
sr, s = r, s[size:]
|
|
}
|
|
if t[0] < utf8.RuneSelf {
|
|
tr, t = rune(t[0]), t[1:]
|
|
} else {
|
|
r, size := utf8.DecodeRuneInString(t)
|
|
tr, t = r, t[size:]
|
|
}
|
|
|
|
// If they match, keep going; if not, return false.
|
|
|
|
// Easy case.
|
|
if tr == sr {
|
|
continue
|
|
}
|
|
|
|
// Make sr < tr to simplify what follows.
|
|
if tr < sr {
|
|
tr, sr = sr, tr
|
|
}
|
|
// Fast check for ASCII.
|
|
if tr < utf8.RuneSelf && 'A' <= sr && sr <= 'Z' {
|
|
// ASCII, and sr is upper case. tr must be lower case.
|
|
if tr == sr+'a'-'A' {
|
|
continue
|
|
}
|
|
return false
|
|
}
|
|
|
|
// General case. SimpleFold(x) returns the next equivalent rune > x
|
|
// or wraps around to smaller values.
|
|
r := unicode.SimpleFold(sr)
|
|
for r != sr && r < tr {
|
|
r = unicode.SimpleFold(r)
|
|
}
|
|
if r == tr {
|
|
continue
|
|
}
|
|
return false
|
|
}
|
|
|
|
// One string is empty. Are both?
|
|
return s == t
|
|
}
|