podman
1// Copyright 2015 Huan Du. All rights reserved.
2// Licensed under the MIT license that can be found in the LICENSE file.
3
4package xstrings5
6import (7"strings"8"unicode/utf8"9)
10
11// Reverse a utf8 encoded string.
12func Reverse(str string) string {13var size int14
15tail := len(str)16buf := make([]byte, tail)17s := buf18
19for len(str) > 0 {20_, size = utf8.DecodeRuneInString(str)21tail -= size22s = append(s[:tail], []byte(str[:size])...)23str = str[size:]24}25
26return string(buf)27}
28
29// Slice a string by rune.
30//
31// Start must satisfy 0 <= start <= rune length.
32//
33// End can be positive, zero or negative.
34// If end >= 0, start and end must satisfy start <= end <= rune length.
35// If end < 0, it means slice to the end of string.
36//
37// Otherwise, Slice will panic as out of range.
38func Slice(str string, start, end int) string {39var size, startPos, endPos int40
41origin := str42
43if start < 0 || end > len(str) || (end >= 0 && start > end) {44panic("out of range")45}46
47if end >= 0 {48end -= start49}50
51for start > 0 && len(str) > 0 {52_, size = utf8.DecodeRuneInString(str)53start--54startPos += size55str = str[size:]56}57
58if end < 0 {59return origin[startPos:]60}61
62endPos = startPos63
64for end > 0 && len(str) > 0 {65_, size = utf8.DecodeRuneInString(str)66end--67endPos += size68str = str[size:]69}70
71if len(str) == 0 && (start > 0 || end > 0) {72panic("out of range")73}74
75return origin[startPos:endPos]76}
77
78// Partition splits a string by sep into three parts.
79// The return value is a slice of strings with head, match and tail.
80//
81// If str contains sep, for example "hello" and "l", Partition returns
82// "he", "l", "lo"
83//
84// If str doesn't contain sep, for example "hello" and "x", Partition returns
85// "hello", "", ""
86func Partition(str, sep string) (head, match, tail string) {87index := strings.Index(str, sep)88
89if index == -1 {90head = str91return92}93
94head = str[:index]95match = str[index : index+len(sep)]96tail = str[index+len(sep):]97return98}
99
100// LastPartition splits a string by last instance of sep into three parts.
101// The return value is a slice of strings with head, match and tail.
102//
103// If str contains sep, for example "hello" and "l", LastPartition returns
104// "hel", "l", "o"
105//
106// If str doesn't contain sep, for example "hello" and "x", LastPartition returns
107// "", "", "hello"
108func LastPartition(str, sep string) (head, match, tail string) {109index := strings.LastIndex(str, sep)110
111if index == -1 {112tail = str113return114}115
116head = str[:index]117match = str[index : index+len(sep)]118tail = str[index+len(sep):]119return120}
121
122// Insert src into dst at given rune index.
123// Index is counted by runes instead of bytes.
124//
125// If index is out of range of dst, panic with out of range.
126func Insert(dst, src string, index int) string {127return Slice(dst, 0, index) + src + Slice(dst, index, -1)128}
129
130// Scrub scrubs invalid utf8 bytes with repl string.
131// Adjacent invalid bytes are replaced only once.
132func Scrub(str, repl string) string {133var buf *stringBuilder134var r rune135var size, pos int136var hasError bool137
138origin := str139
140for len(str) > 0 {141r, size = utf8.DecodeRuneInString(str)142
143if r == utf8.RuneError {144if !hasError {145if buf == nil {146buf = &stringBuilder{}147}148
149buf.WriteString(origin[:pos])150hasError = true151}152} else if hasError {153hasError = false154buf.WriteString(repl)155
156origin = origin[pos:]157pos = 0158}159
160pos += size161str = str[size:]162}163
164if buf != nil {165buf.WriteString(origin)166return buf.String()167}168
169// No invalid byte.170return origin171}
172
173// WordSplit splits a string into words. Returns a slice of words.
174// If there is no word in a string, return nil.
175//
176// Word is defined as a locale dependent string containing alphabetic characters,
177// which may also contain but not start with `'` and `-` characters.
178func WordSplit(str string) []string {179var word string180var words []string181var r rune182var size, pos int183
184inWord := false185
186for len(str) > 0 {187r, size = utf8.DecodeRuneInString(str)188
189switch {190case isAlphabet(r):191if !inWord {192inWord = true193word = str194pos = 0195}196
197case inWord && (r == '\'' || r == '-'):198// Still in word.199
200default:201if inWord {202inWord = false203words = append(words, word[:pos])204}205}206
207pos += size208str = str[size:]209}210
211if inWord {212words = append(words, word[:pos])213}214
215return words216}
217