| | |
| | |
| | |
| |
|
| | |
| | |
| | package bytes |
| |
|
| | import ( |
| | "internal/bytealg" |
| | "math/bits" |
| | "unicode" |
| | "unicode/utf8" |
| | _ "unsafe" |
| | ) |
| |
|
| | |
| | |
| | |
| | func Equal(a, b []byte) bool { |
| | |
| | return string(a) == string(b) |
| | } |
| |
|
| | |
| | |
| | |
| | func Compare(a, b []byte) int { |
| | return bytealg.Compare(a, b) |
| | } |
| |
|
| | |
| | |
| | func explode(s []byte, n int) [][]byte { |
| | if n <= 0 || n > len(s) { |
| | n = len(s) |
| | } |
| | a := make([][]byte, n) |
| | var size int |
| | na := 0 |
| | for len(s) > 0 { |
| | if na+1 >= n { |
| | a[na] = s |
| | na++ |
| | break |
| | } |
| | _, size = utf8.DecodeRune(s) |
| | a[na] = s[0:size:size] |
| | s = s[size:] |
| | na++ |
| | } |
| | return a[0:na] |
| | } |
| |
|
| | |
| | |
| | func Count(s, sep []byte) int { |
| | |
| | if len(sep) == 0 { |
| | return utf8.RuneCount(s) + 1 |
| | } |
| | if len(sep) == 1 { |
| | return bytealg.Count(s, sep[0]) |
| | } |
| | n := 0 |
| | for { |
| | i := Index(s, sep) |
| | if i == -1 { |
| | return n |
| | } |
| | n++ |
| | s = s[i+len(sep):] |
| | } |
| | } |
| |
|
| | |
| | func Contains(b, subslice []byte) bool { |
| | return Index(b, subslice) != -1 |
| | } |
| |
|
| | |
| | func ContainsAny(b []byte, chars string) bool { |
| | return IndexAny(b, chars) >= 0 |
| | } |
| |
|
| | |
| | func ContainsRune(b []byte, r rune) bool { |
| | return IndexRune(b, r) >= 0 |
| | } |
| |
|
| | |
| | func ContainsFunc(b []byte, f func(rune) bool) bool { |
| | return IndexFunc(b, f) >= 0 |
| | } |
| |
|
| | |
| | func IndexByte(b []byte, c byte) int { |
| | return bytealg.IndexByte(b, c) |
| | } |
| |
|
| | func indexBytePortable(s []byte, c byte) int { |
| | for i, b := range s { |
| | if b == c { |
| | return i |
| | } |
| | } |
| | return -1 |
| | } |
| |
|
| | |
| | func LastIndex(s, sep []byte) int { |
| | n := len(sep) |
| | switch { |
| | case n == 0: |
| | return len(s) |
| | case n == 1: |
| | return bytealg.LastIndexByte(s, sep[0]) |
| | case n == len(s): |
| | if Equal(s, sep) { |
| | return 0 |
| | } |
| | return -1 |
| | case n > len(s): |
| | return -1 |
| | } |
| | return bytealg.LastIndexRabinKarp(s, sep) |
| | } |
| |
|
| | |
| | func LastIndexByte(s []byte, c byte) int { |
| | return bytealg.LastIndexByte(s, c) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func IndexRune(s []byte, r rune) int { |
| | const haveFastIndex = bytealg.MaxBruteForce > 0 |
| | switch { |
| | case 0 <= r && r < utf8.RuneSelf: |
| | return IndexByte(s, byte(r)) |
| | case r == utf8.RuneError: |
| | for i := 0; i < len(s); { |
| | r1, n := utf8.DecodeRune(s[i:]) |
| | if r1 == utf8.RuneError { |
| | return i |
| | } |
| | i += n |
| | } |
| | return -1 |
| | case !utf8.ValidRune(r): |
| | return -1 |
| | default: |
| | |
| | |
| | |
| | var b [utf8.UTFMax]byte |
| | n := utf8.EncodeRune(b[:], r) |
| | last := n - 1 |
| | i := last |
| | fails := 0 |
| | for i < len(s) { |
| | if s[i] != b[last] { |
| | o := IndexByte(s[i+1:], b[last]) |
| | if o < 0 { |
| | return -1 |
| | } |
| | i += o + 1 |
| | } |
| | |
| | for j := 1; j < n; j++ { |
| | if s[i-j] != b[last-j] { |
| | goto next |
| | } |
| | } |
| | return i - last |
| | next: |
| | fails++ |
| | i++ |
| | if (haveFastIndex && fails > bytealg.Cutover(i)) && i < len(s) || |
| | (!haveFastIndex && fails >= 4+i>>4 && i < len(s)) { |
| | goto fallback |
| | } |
| | } |
| | return -1 |
| |
|
| | fallback: |
| | |
| | |
| | if haveFastIndex { |
| | if j := bytealg.Index(s[i-last:], b[:n]); j >= 0 { |
| | return i + j - last |
| | } |
| | } else { |
| | |
| | |
| | c0 := b[last] |
| | c1 := b[last-1] |
| | loop: |
| | for ; i < len(s); i++ { |
| | if s[i] == c0 && s[i-1] == c1 { |
| | for k := 2; k < n; k++ { |
| | if s[i-k] != b[last-k] { |
| | continue loop |
| | } |
| | } |
| | return i - last |
| | } |
| | } |
| | } |
| | return -1 |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func IndexAny(s []byte, chars string) int { |
| | if chars == "" { |
| | |
| | return -1 |
| | } |
| | if len(s) == 1 { |
| | r := rune(s[0]) |
| | if r >= utf8.RuneSelf { |
| | |
| | for _, r = range chars { |
| | if r == utf8.RuneError { |
| | return 0 |
| | } |
| | } |
| | return -1 |
| | } |
| | if bytealg.IndexByteString(chars, s[0]) >= 0 { |
| | return 0 |
| | } |
| | return -1 |
| | } |
| | if len(chars) == 1 { |
| | r := rune(chars[0]) |
| | if r >= utf8.RuneSelf { |
| | r = utf8.RuneError |
| | } |
| | return IndexRune(s, r) |
| | } |
| | if len(s) > 8 { |
| | if as, isASCII := makeASCIISet(chars); isASCII { |
| | for i, c := range s { |
| | if as.contains(c) { |
| | return i |
| | } |
| | } |
| | return -1 |
| | } |
| | } |
| | var width int |
| | for i := 0; i < len(s); i += width { |
| | r := rune(s[i]) |
| | if r < utf8.RuneSelf { |
| | if bytealg.IndexByteString(chars, s[i]) >= 0 { |
| | return i |
| | } |
| | width = 1 |
| | continue |
| | } |
| | r, width = utf8.DecodeRune(s[i:]) |
| | if r != utf8.RuneError { |
| | |
| | if len(chars) == width { |
| | if chars == string(r) { |
| | return i |
| | } |
| | continue |
| | } |
| | |
| | if bytealg.MaxLen >= width { |
| | if bytealg.IndexString(chars, string(r)) >= 0 { |
| | return i |
| | } |
| | continue |
| | } |
| | } |
| | for _, ch := range chars { |
| | if r == ch { |
| | return i |
| | } |
| | } |
| | } |
| | return -1 |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func LastIndexAny(s []byte, chars string) int { |
| | if chars == "" { |
| | |
| | return -1 |
| | } |
| | if len(s) > 8 { |
| | if as, isASCII := makeASCIISet(chars); isASCII { |
| | for i := len(s) - 1; i >= 0; i-- { |
| | if as.contains(s[i]) { |
| | return i |
| | } |
| | } |
| | return -1 |
| | } |
| | } |
| | if len(s) == 1 { |
| | r := rune(s[0]) |
| | if r >= utf8.RuneSelf { |
| | for _, r = range chars { |
| | if r == utf8.RuneError { |
| | return 0 |
| | } |
| | } |
| | return -1 |
| | } |
| | if bytealg.IndexByteString(chars, s[0]) >= 0 { |
| | return 0 |
| | } |
| | return -1 |
| | } |
| | if len(chars) == 1 { |
| | cr := rune(chars[0]) |
| | if cr >= utf8.RuneSelf { |
| | cr = utf8.RuneError |
| | } |
| | for i := len(s); i > 0; { |
| | r, size := utf8.DecodeLastRune(s[:i]) |
| | i -= size |
| | if r == cr { |
| | return i |
| | } |
| | } |
| | return -1 |
| | } |
| | for i := len(s); i > 0; { |
| | r := rune(s[i-1]) |
| | if r < utf8.RuneSelf { |
| | if bytealg.IndexByteString(chars, s[i-1]) >= 0 { |
| | return i - 1 |
| | } |
| | i-- |
| | continue |
| | } |
| | r, size := utf8.DecodeLastRune(s[:i]) |
| | i -= size |
| | if r != utf8.RuneError { |
| | |
| | if len(chars) == size { |
| | if chars == string(r) { |
| | return i |
| | } |
| | continue |
| | } |
| | |
| | if bytealg.MaxLen >= size { |
| | if bytealg.IndexString(chars, string(r)) >= 0 { |
| | return i |
| | } |
| | continue |
| | } |
| | } |
| | for _, ch := range chars { |
| | if r == ch { |
| | return i |
| | } |
| | } |
| | } |
| | return -1 |
| | } |
| |
|
| | |
| | |
| | func genSplit(s, sep []byte, sepSave, n int) [][]byte { |
| | if n == 0 { |
| | return nil |
| | } |
| | if len(sep) == 0 { |
| | return explode(s, n) |
| | } |
| | if n < 0 { |
| | n = Count(s, sep) + 1 |
| | } |
| | if n > len(s)+1 { |
| | n = len(s) + 1 |
| | } |
| |
|
| | a := make([][]byte, n) |
| | n-- |
| | i := 0 |
| | for i < n { |
| | m := Index(s, sep) |
| | if m < 0 { |
| | break |
| | } |
| | a[i] = s[: m+sepSave : m+sepSave] |
| | s = s[m+len(sep):] |
| | i++ |
| | } |
| | a[i] = s |
| | return a[:i+1] |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func SplitAfterN(s, sep []byte, n int) [][]byte { |
| | return genSplit(s, sep, len(sep), n) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) } |
| |
|
| | |
| | |
| | |
| | |
| | func SplitAfter(s, sep []byte) [][]byte { |
| | return genSplit(s, sep, len(sep), -1) |
| | } |
| |
|
| | var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func Fields(s []byte) [][]byte { |
| | |
| | |
| | n := 0 |
| | wasSpace := 1 |
| | |
| | setBits := uint8(0) |
| | for i := 0; i < len(s); i++ { |
| | r := s[i] |
| | setBits |= r |
| | isSpace := int(asciiSpace[r]) |
| | n += wasSpace & ^isSpace |
| | wasSpace = isSpace |
| | } |
| |
|
| | if setBits >= utf8.RuneSelf { |
| | |
| | return FieldsFunc(s, unicode.IsSpace) |
| | } |
| |
|
| | |
| | a := make([][]byte, n) |
| | na := 0 |
| | fieldStart := 0 |
| | i := 0 |
| | |
| | for i < len(s) && asciiSpace[s[i]] != 0 { |
| | i++ |
| | } |
| | fieldStart = i |
| | for i < len(s) { |
| | if asciiSpace[s[i]] == 0 { |
| | i++ |
| | continue |
| | } |
| | a[na] = s[fieldStart:i:i] |
| | na++ |
| | i++ |
| | |
| | for i < len(s) && asciiSpace[s[i]] != 0 { |
| | i++ |
| | } |
| | fieldStart = i |
| | } |
| | if fieldStart < len(s) { |
| | a[na] = s[fieldStart:len(s):len(s)] |
| | } |
| | return a |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func FieldsFunc(s []byte, f func(rune) bool) [][]byte { |
| | |
| | |
| | type span struct { |
| | start int |
| | end int |
| | } |
| | spans := make([]span, 0, 32) |
| |
|
| | |
| | |
| | |
| | |
| | start := -1 |
| | for i := 0; i < len(s); { |
| | r, size := utf8.DecodeRune(s[i:]) |
| | if f(r) { |
| | if start >= 0 { |
| | spans = append(spans, span{start, i}) |
| | start = -1 |
| | } |
| | } else { |
| | if start < 0 { |
| | start = i |
| | } |
| | } |
| | i += size |
| | } |
| |
|
| | |
| | if start >= 0 { |
| | spans = append(spans, span{start, len(s)}) |
| | } |
| |
|
| | |
| | a := make([][]byte, len(spans)) |
| | for i, span := range spans { |
| | a[i] = s[span.start:span.end:span.end] |
| | } |
| |
|
| | return a |
| | } |
| |
|
| | |
| | |
| | func Join(s [][]byte, sep []byte) []byte { |
| | if len(s) == 0 { |
| | return []byte{} |
| | } |
| | if len(s) == 1 { |
| | |
| | return append([]byte(nil), s[0]...) |
| | } |
| |
|
| | var n int |
| | if len(sep) > 0 { |
| | if len(sep) >= maxInt/(len(s)-1) { |
| | panic("bytes: Join output length overflow") |
| | } |
| | n += len(sep) * (len(s) - 1) |
| | } |
| | for _, v := range s { |
| | if len(v) > maxInt-n { |
| | panic("bytes: Join output length overflow") |
| | } |
| | n += len(v) |
| | } |
| |
|
| | b := bytealg.MakeNoZero(n)[:n:n] |
| | bp := copy(b, s[0]) |
| | for _, v := range s[1:] { |
| | bp += copy(b[bp:], sep) |
| | bp += copy(b[bp:], v) |
| | } |
| | return b |
| | } |
| |
|
| | |
| | func HasPrefix(s, prefix []byte) bool { |
| | return len(s) >= len(prefix) && Equal(s[:len(prefix)], prefix) |
| | } |
| |
|
| | |
| | func HasSuffix(s, suffix []byte) bool { |
| | return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):], suffix) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func Map(mapping func(r rune) rune, s []byte) []byte { |
| | |
| | |
| | |
| | b := make([]byte, 0, len(s)) |
| | for i := 0; i < len(s); { |
| | r, wid := utf8.DecodeRune(s[i:]) |
| | r = mapping(r) |
| | if r >= 0 { |
| | b = utf8.AppendRune(b, r) |
| | } |
| | i += wid |
| | } |
| | return b |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | func Repeat(b []byte, count int) []byte { |
| | if count == 0 { |
| | return []byte{} |
| | } |
| |
|
| | |
| | |
| | |
| | if count < 0 { |
| | panic("bytes: negative Repeat count") |
| | } |
| | hi, lo := bits.Mul(uint(len(b)), uint(count)) |
| | if hi > 0 || lo > uint(maxInt) { |
| | panic("bytes: Repeat output length overflow") |
| | } |
| | n := int(lo) |
| |
|
| | if len(b) == 0 { |
| | return []byte{} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const chunkLimit = 8 * 1024 |
| | chunkMax := n |
| | if chunkMax > chunkLimit { |
| | chunkMax = chunkLimit / len(b) * len(b) |
| | if chunkMax == 0 { |
| | chunkMax = len(b) |
| | } |
| | } |
| | nb := bytealg.MakeNoZero(n)[:n:n] |
| | bp := copy(nb, b) |
| | for bp < n { |
| | chunk := min(bp, chunkMax) |
| | bp += copy(nb[bp:], nb[:chunk]) |
| | } |
| | return nb |
| | } |
| |
|
| | |
| | |
| | func ToUpper(s []byte) []byte { |
| | isASCII, hasLower := true, false |
| | for i := 0; i < len(s); i++ { |
| | c := s[i] |
| | if c >= utf8.RuneSelf { |
| | isASCII = false |
| | break |
| | } |
| | hasLower = hasLower || ('a' <= c && c <= 'z') |
| | } |
| |
|
| | if isASCII { |
| | if !hasLower { |
| | |
| | return append([]byte(""), s...) |
| | } |
| | b := bytealg.MakeNoZero(len(s))[:len(s):len(s)] |
| | for i := 0; i < len(s); i++ { |
| | c := s[i] |
| | if 'a' <= c && c <= 'z' { |
| | c -= 'a' - 'A' |
| | } |
| | b[i] = c |
| | } |
| | return b |
| | } |
| | return Map(unicode.ToUpper, s) |
| | } |
| |
|
| | |
| | |
| | func ToLower(s []byte) []byte { |
| | isASCII, hasUpper := true, false |
| | for i := 0; i < len(s); i++ { |
| | c := s[i] |
| | if c >= utf8.RuneSelf { |
| | isASCII = false |
| | break |
| | } |
| | hasUpper = hasUpper || ('A' <= c && c <= 'Z') |
| | } |
| |
|
| | if isASCII { |
| | if !hasUpper { |
| | return append([]byte(""), s...) |
| | } |
| | b := bytealg.MakeNoZero(len(s))[:len(s):len(s)] |
| | for i := 0; i < len(s); i++ { |
| | c := s[i] |
| | if 'A' <= c && c <= 'Z' { |
| | c += 'a' - 'A' |
| | } |
| | b[i] = c |
| | } |
| | return b |
| | } |
| | return Map(unicode.ToLower, s) |
| | } |
| |
|
| | |
| | func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) } |
| |
|
| | |
| | |
| | func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte { |
| | return Map(c.ToUpper, s) |
| | } |
| |
|
| | |
| | |
| | func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte { |
| | return Map(c.ToLower, s) |
| | } |
| |
|
| | |
| | |
| | func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte { |
| | return Map(c.ToTitle, s) |
| | } |
| |
|
| | |
| | |
| | func ToValidUTF8(s, replacement []byte) []byte { |
| | b := make([]byte, 0, len(s)+len(replacement)) |
| | invalid := false |
| | for i := 0; i < len(s); { |
| | c := s[i] |
| | if c < utf8.RuneSelf { |
| | i++ |
| | invalid = false |
| | b = append(b, c) |
| | continue |
| | } |
| | _, wid := utf8.DecodeRune(s[i:]) |
| | if wid == 1 { |
| | i++ |
| | if !invalid { |
| | invalid = true |
| | b = append(b, replacement...) |
| | } |
| | continue |
| | } |
| | invalid = false |
| | b = append(b, s[i:i+wid]...) |
| | i += wid |
| | } |
| | return b |
| | } |
| |
|
| | |
| | |
| | func isSeparator(r rune) bool { |
| | |
| | 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 |
| | } |
| | |
| | if unicode.IsLetter(r) || unicode.IsDigit(r) { |
| | return false |
| | } |
| | |
| | return unicode.IsSpace(r) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func Title(s []byte) []byte { |
| | |
| | |
| | |
| | prev := ' ' |
| | return Map( |
| | func(r rune) rune { |
| | if isSeparator(prev) { |
| | prev = r |
| | return unicode.ToTitle(r) |
| | } |
| | prev = r |
| | return r |
| | }, |
| | s) |
| | } |
| |
|
| | |
| | |
| | func TrimLeftFunc(s []byte, f func(r rune) bool) []byte { |
| | i := indexFunc(s, f, false) |
| | if i == -1 { |
| | return nil |
| | } |
| | return s[i:] |
| | } |
| |
|
| | |
| | |
| | func TrimRightFunc(s []byte, f func(r rune) bool) []byte { |
| | i := lastIndexFunc(s, f, false) |
| | if i >= 0 && s[i] >= utf8.RuneSelf { |
| | _, wid := utf8.DecodeRune(s[i:]) |
| | i += wid |
| | } else { |
| | i++ |
| | } |
| | return s[0:i] |
| | } |
| |
|
| | |
| | |
| | func TrimFunc(s []byte, f func(r rune) bool) []byte { |
| | return TrimRightFunc(TrimLeftFunc(s, f), f) |
| | } |
| |
|
| | |
| | |
| | func TrimPrefix(s, prefix []byte) []byte { |
| | if HasPrefix(s, prefix) { |
| | return s[len(prefix):] |
| | } |
| | return s |
| | } |
| |
|
| | |
| | |
| | func TrimSuffix(s, suffix []byte) []byte { |
| | if HasSuffix(s, suffix) { |
| | return s[:len(s)-len(suffix)] |
| | } |
| | return s |
| | } |
| |
|
| | |
| | |
| | |
| | func IndexFunc(s []byte, f func(r rune) bool) int { |
| | return indexFunc(s, f, true) |
| | } |
| |
|
| | |
| | |
| | |
| | func LastIndexFunc(s []byte, f func(r rune) bool) int { |
| | return lastIndexFunc(s, f, true) |
| | } |
| |
|
| | |
| | |
| | |
| | func indexFunc(s []byte, f func(r rune) bool, truth bool) int { |
| | start := 0 |
| | for start < len(s) { |
| | r, wid := utf8.DecodeRune(s[start:]) |
| | if f(r) == truth { |
| | return start |
| | } |
| | start += wid |
| | } |
| | return -1 |
| | } |
| |
|
| | |
| | |
| | |
| | func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int { |
| | for i := len(s); i > 0; { |
| | r, size := rune(s[i-1]), 1 |
| | if r >= utf8.RuneSelf { |
| | r, size = utf8.DecodeLastRune(s[0:i]) |
| | } |
| | i -= size |
| | if f(r) == truth { |
| | return i |
| | } |
| | } |
| | return -1 |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type asciiSet [8]uint32 |
| |
|
| | |
| | |
| | func makeASCIISet(chars string) (as asciiSet, ok bool) { |
| | for i := 0; i < len(chars); i++ { |
| | c := chars[i] |
| | if c >= utf8.RuneSelf { |
| | return as, false |
| | } |
| | as[c/32] |= 1 << (c % 32) |
| | } |
| | return as, true |
| | } |
| |
|
| | |
| | func (as *asciiSet) contains(c byte) bool { |
| | return (as[c/32] & (1 << (c % 32))) != 0 |
| | } |
| |
|
| | |
| | |
| | |
| | func containsRune(s string, r rune) bool { |
| | for _, c := range s { |
| | if c == r { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | func Trim(s []byte, cutset string) []byte { |
| | if len(s) == 0 { |
| | |
| | return nil |
| | } |
| | if cutset == "" { |
| | return s |
| | } |
| | if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { |
| | return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0]) |
| | } |
| | if as, ok := makeASCIISet(cutset); ok { |
| | return trimLeftASCII(trimRightASCII(s, &as), &as) |
| | } |
| | return trimLeftUnicode(trimRightUnicode(s, cutset), cutset) |
| | } |
| |
|
| | |
| | |
| | func TrimLeft(s []byte, cutset string) []byte { |
| | if len(s) == 0 { |
| | |
| | return nil |
| | } |
| | if cutset == "" { |
| | return s |
| | } |
| | if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { |
| | return trimLeftByte(s, cutset[0]) |
| | } |
| | if as, ok := makeASCIISet(cutset); ok { |
| | return trimLeftASCII(s, &as) |
| | } |
| | return trimLeftUnicode(s, cutset) |
| | } |
| |
|
| | func trimLeftByte(s []byte, c byte) []byte { |
| | for len(s) > 0 && s[0] == c { |
| | s = s[1:] |
| | } |
| | if len(s) == 0 { |
| | |
| | return nil |
| | } |
| | return s |
| | } |
| |
|
| | func trimLeftASCII(s []byte, as *asciiSet) []byte { |
| | for len(s) > 0 { |
| | if !as.contains(s[0]) { |
| | break |
| | } |
| | s = s[1:] |
| | } |
| | if len(s) == 0 { |
| | |
| | return nil |
| | } |
| | return s |
| | } |
| |
|
| | func trimLeftUnicode(s []byte, cutset string) []byte { |
| | for len(s) > 0 { |
| | r, n := utf8.DecodeRune(s) |
| | if !containsRune(cutset, r) { |
| | break |
| | } |
| | s = s[n:] |
| | } |
| | if len(s) == 0 { |
| | |
| | return nil |
| | } |
| | return s |
| | } |
| |
|
| | |
| | |
| | func TrimRight(s []byte, cutset string) []byte { |
| | if len(s) == 0 || cutset == "" { |
| | return s |
| | } |
| | if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { |
| | return trimRightByte(s, cutset[0]) |
| | } |
| | if as, ok := makeASCIISet(cutset); ok { |
| | return trimRightASCII(s, &as) |
| | } |
| | return trimRightUnicode(s, cutset) |
| | } |
| |
|
| | func trimRightByte(s []byte, c byte) []byte { |
| | for len(s) > 0 && s[len(s)-1] == c { |
| | s = s[:len(s)-1] |
| | } |
| | return s |
| | } |
| |
|
| | func trimRightASCII(s []byte, as *asciiSet) []byte { |
| | for len(s) > 0 { |
| | if !as.contains(s[len(s)-1]) { |
| | break |
| | } |
| | s = s[:len(s)-1] |
| | } |
| | return s |
| | } |
| |
|
| | func trimRightUnicode(s []byte, cutset string) []byte { |
| | for len(s) > 0 { |
| | r, n := rune(s[len(s)-1]), 1 |
| | if r >= utf8.RuneSelf { |
| | r, n = utf8.DecodeLastRune(s) |
| | } |
| | if !containsRune(cutset, r) { |
| | break |
| | } |
| | s = s[:len(s)-n] |
| | } |
| | return s |
| | } |
| |
|
| | |
| | |
| | func TrimSpace(s []byte) []byte { |
| | |
| | for lo, c := range s { |
| | if c >= utf8.RuneSelf { |
| | |
| | |
| | return TrimFunc(s[lo:], unicode.IsSpace) |
| | } |
| | if asciiSpace[c] != 0 { |
| | continue |
| | } |
| | s = s[lo:] |
| | |
| | for hi := len(s) - 1; hi >= 0; hi-- { |
| | c := s[hi] |
| | if c >= utf8.RuneSelf { |
| | return TrimFunc(s[:hi+1], unicode.IsSpace) |
| | } |
| | if asciiSpace[c] == 0 { |
| | |
| | |
| | |
| | return s[:hi+1] |
| | } |
| | } |
| | } |
| | |
| | |
| | return nil |
| | } |
| |
|
| | |
| | |
| | func Runes(s []byte) []rune { |
| | t := make([]rune, utf8.RuneCount(s)) |
| | i := 0 |
| | for len(s) > 0 { |
| | r, l := utf8.DecodeRune(s) |
| | t[i] = r |
| | i++ |
| | s = s[l:] |
| | } |
| | return t |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func Replace(s, old, new []byte, n int) []byte { |
| | m := 0 |
| | if n != 0 { |
| | |
| | m = Count(s, old) |
| | } |
| | if m == 0 { |
| | |
| | return append([]byte(nil), s...) |
| | } |
| | if n < 0 || m < n { |
| | n = m |
| | } |
| |
|
| | |
| | t := make([]byte, len(s)+n*(len(new)-len(old))) |
| | w := 0 |
| | start := 0 |
| | if len(old) > 0 { |
| | for range n { |
| | j := start + Index(s[start:], old) |
| | w += copy(t[w:], s[start:j]) |
| | w += copy(t[w:], new) |
| | start = j + len(old) |
| | } |
| | } else { |
| | w += copy(t[w:], new) |
| | for range n - 1 { |
| | _, wid := utf8.DecodeRune(s[start:]) |
| | j := start + wid |
| | w += copy(t[w:], s[start:j]) |
| | w += copy(t[w:], new) |
| | start = j |
| | } |
| | } |
| | w += copy(t[w:], s[start:]) |
| | return t[0:w] |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func ReplaceAll(s, old, new []byte) []byte { |
| | return Replace(s, old, new, -1) |
| | } |
| |
|
| | |
| | |
| | |
| | func EqualFold(s, t []byte) bool { |
| | |
| | i := 0 |
| | for n := min(len(s), len(t)); i < n; i++ { |
| | sr := s[i] |
| | tr := t[i] |
| | if sr|tr >= utf8.RuneSelf { |
| | goto hasUnicode |
| | } |
| |
|
| | |
| | if tr == sr { |
| | continue |
| | } |
| |
|
| | |
| | if tr < sr { |
| | tr, sr = sr, tr |
| | } |
| | |
| | if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { |
| | continue |
| | } |
| | return false |
| | } |
| | |
| | return len(s) == len(t) |
| |
|
| | hasUnicode: |
| | s = s[i:] |
| | t = t[i:] |
| | for len(s) != 0 && len(t) != 0 { |
| | |
| | sr, size := utf8.DecodeRune(s) |
| | s = s[size:] |
| | tr, size := utf8.DecodeRune(t) |
| | t = t[size:] |
| |
|
| | |
| |
|
| | |
| | if tr == sr { |
| | continue |
| | } |
| |
|
| | |
| | if tr < sr { |
| | tr, sr = sr, tr |
| | } |
| | |
| | if tr < utf8.RuneSelf { |
| | |
| | if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { |
| | continue |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | r := unicode.SimpleFold(sr) |
| | for r != sr && r < tr { |
| | r = unicode.SimpleFold(r) |
| | } |
| | if r == tr { |
| | continue |
| | } |
| | return false |
| | } |
| |
|
| | |
| | return len(s) == len(t) |
| | } |
| |
|
| | |
| | func Index(s, sep []byte) int { |
| | n := len(sep) |
| | switch { |
| | case n == 0: |
| | return 0 |
| | case n == 1: |
| | return IndexByte(s, sep[0]) |
| | case n == len(s): |
| | if Equal(sep, s) { |
| | return 0 |
| | } |
| | return -1 |
| | case n > len(s): |
| | return -1 |
| | case n <= bytealg.MaxLen: |
| | |
| | if len(s) <= bytealg.MaxBruteForce { |
| | return bytealg.Index(s, sep) |
| | } |
| | c0 := sep[0] |
| | c1 := sep[1] |
| | i := 0 |
| | t := len(s) - n + 1 |
| | fails := 0 |
| | for i < t { |
| | if s[i] != c0 { |
| | |
| | |
| | o := IndexByte(s[i+1:t], c0) |
| | if o < 0 { |
| | return -1 |
| | } |
| | i += o + 1 |
| | } |
| | if s[i+1] == c1 && Equal(s[i:i+n], sep) { |
| | return i |
| | } |
| | fails++ |
| | i++ |
| | |
| | if fails > bytealg.Cutover(i) { |
| | r := bytealg.Index(s[i:], sep) |
| | if r >= 0 { |
| | return r + i |
| | } |
| | return -1 |
| | } |
| | } |
| | return -1 |
| | } |
| | c0 := sep[0] |
| | c1 := sep[1] |
| | i := 0 |
| | fails := 0 |
| | t := len(s) - n + 1 |
| | for i < t { |
| | if s[i] != c0 { |
| | o := IndexByte(s[i+1:t], c0) |
| | if o < 0 { |
| | break |
| | } |
| | i += o + 1 |
| | } |
| | if s[i+1] == c1 && Equal(s[i:i+n], sep) { |
| | return i |
| | } |
| | i++ |
| | fails++ |
| | if fails >= 4+i>>4 && i < t { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | j := bytealg.IndexRabinKarp(s[i:], sep) |
| | if j < 0 { |
| | return -1 |
| | } |
| | return i + j |
| | } |
| | } |
| | return -1 |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func Cut(s, sep []byte) (before, after []byte, found bool) { |
| | if i := Index(s, sep); i >= 0 { |
| | return s[:i], s[i+len(sep):], true |
| | } |
| | return s, nil, false |
| | } |
| |
|
| | |
| | |
| | |
| | func Clone(b []byte) []byte { |
| | if b == nil { |
| | return nil |
| | } |
| | return append([]byte{}, b...) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func CutPrefix(s, prefix []byte) (after []byte, found bool) { |
| | if !HasPrefix(s, prefix) { |
| | return s, false |
| | } |
| | return s[len(prefix):], true |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func CutSuffix(s, suffix []byte) (before []byte, found bool) { |
| | if !HasSuffix(s, suffix) { |
| | return s, false |
| | } |
| | return s[:len(s)-len(suffix)], true |
| | } |
| |
|