github.com/enetx/g@v1.0.80/bytes.go (about) 1 package g 2 3 import ( 4 "bytes" 5 "fmt" 6 "regexp" 7 "unicode/utf8" 8 9 "github.com/enetx/g/cmp" 10 "golang.org/x/text/cases" 11 "golang.org/x/text/language" 12 "golang.org/x/text/unicode/norm" 13 ) 14 15 // NewBytes creates a new Bytes value. 16 func NewBytes[T ~string | ~[]byte](bs T) Bytes { return Bytes(bs) } 17 18 // Reverse returns a new Bytes with the order of its runes reversed. 19 func (bs Bytes) Reverse() Bytes { 20 reversed := make(Bytes, bs.Len()) 21 i := 0 22 23 for bs.Len() > 0 { 24 r, size := utf8.DecodeLastRune(bs) 25 bs = bs[:bs.Len().Std()-size] 26 i += utf8.EncodeRune(reversed[i:], r) 27 } 28 29 return reversed 30 } 31 32 // Replace replaces the first 'n' occurrences of 'oldB' with 'newB' in the Bytes. 33 func (bs Bytes) Replace(oldB, newB Bytes, n Int) Bytes { return bytes.Replace(bs, oldB, newB, n.Std()) } 34 35 // ReplaceAll replaces all occurrences of 'oldB' with 'newB' in the Bytes. 36 func (bs Bytes) ReplaceAll(oldB, newB Bytes) Bytes { return bytes.ReplaceAll(bs, oldB, newB) } 37 38 // ReplaceRegexp replaces all occurrences of the regular expression matches in the Bytes 39 // with the provided newB and returns the resulting Bytes after the replacement. 40 func (bs Bytes) ReplaceRegexp(pattern *regexp.Regexp, newB Bytes) Bytes { 41 return pattern.ReplaceAll(bs, newB) 42 } 43 44 // FindRegexp searches the Bytes for the first occurrence of the regular expression pattern 45 // and returns an Option[Bytes] containing the matched substring. 46 // If no match is found, the Option[Bytes] will be None. 47 func (bs Bytes) FindRegexp(pattern *regexp.Regexp) Option[Bytes] { 48 result := Bytes(pattern.Find(bs)) 49 if result.Empty() { 50 return None[Bytes]() 51 } 52 53 return Some(result) 54 } 55 56 // Trim trims the specified characters from the beginning and end of the Bytes. 57 func (bs Bytes) Trim(cutset String) Bytes { return bytes.Trim(bs, cutset.Std()) } 58 59 // TrimLeft trims the specified characters from the beginning of the Bytes. 60 func (bs Bytes) TrimLeft(cutset String) Bytes { return bytes.TrimLeft(bs, cutset.Std()) } 61 62 // TrimRight trims the specified characters from the end of the Bytes. 63 func (bs Bytes) TrimRight(cutset String) Bytes { return bytes.TrimRight(bs, cutset.Std()) } 64 65 // TrimPrefix trims the specified Bytes prefix from the Bytes. 66 func (bs Bytes) TrimPrefix(cutset Bytes) Bytes { return bytes.TrimPrefix(bs, cutset) } 67 68 // TrimSuffix trims the specified Bytes suffix from the Bytes. 69 func (bs Bytes) TrimSuffix(cutset Bytes) Bytes { return bytes.TrimSuffix(bs, cutset) } 70 71 // Split splits the Bytes by the specified separator and returns the iterator. 72 func (bs Bytes) Split(sep ...Bytes) SeqSlice[Bytes] { 73 var separator []byte 74 if len(sep) != 0 { 75 separator = sep[0] 76 } 77 78 return splitBytes(bs, separator, 0) 79 } 80 81 // SplitAfter splits the Bytes after each instance of the specified separator and returns the iterator. 82 func (bs Bytes) SplitAfter(sep Bytes) SeqSlice[Bytes] { return splitBytes(bs, sep, sep.Len()) } 83 84 // Fields splits the Bytes into a slice of substrings, removing any whitespace, and returns the iterator. 85 func (bs Bytes) Fields() SeqSlice[Bytes] { return fieldsBytes(bs) } 86 87 // FieldsBy splits the Bytes into a slice of substrings using a custom function to determine the field boundaries, 88 // and returns the iterator. 89 func (bs Bytes) FieldsBy(fn func(r rune) bool) SeqSlice[Bytes] { return fieldsbyBytes(bs, fn) } 90 91 // Add appends the given Bytes to the current Bytes. 92 func (bs Bytes) Add(obs Bytes) Bytes { return append(bs, obs...) } 93 94 // AddPrefix prepends the given Bytes to the current Bytes. 95 func (bs Bytes) AddPrefix(obs Bytes) Bytes { return obs.Add(bs) } 96 97 // Std returns the Bytes as a byte slice. 98 func (bs Bytes) Std() []byte { return bs } 99 100 // Clone creates a new Bytes instance with the same content as the current Bytes. 101 func (bs Bytes) Clone() Bytes { return bytes.Clone(bs) } 102 103 // Compare compares the Bytes with another Bytes and returns an cmp.Ordering. 104 func (bs Bytes) Cmp(obs Bytes) cmp.Ordering { return cmp.Ordering(bytes.Compare(bs, obs)) } 105 106 // Contains checks if the Bytes contains the specified Bytes. 107 func (bs Bytes) Contains(obs Bytes) bool { return bytes.Contains(bs, obs) } 108 109 // ContainsAny checks if the Bytes contains any of the specified Bytes. 110 func (bs Bytes) ContainsAny(obss ...Bytes) bool { 111 for _, obs := range obss { 112 if bs.Contains(obs) { 113 return true 114 } 115 } 116 117 return false 118 } 119 120 // ContainsAll checks if the Bytes contains all of the specified Bytes. 121 func (bs Bytes) ContainsAll(obss ...Bytes) bool { 122 for _, obs := range obss { 123 if !bs.Contains(obs) { 124 return false 125 } 126 } 127 128 return true 129 } 130 131 // ContainsAnyChars checks if the given Bytes contains any characters from the input String. 132 func (bs Bytes) ContainsAnyChars(chars String) bool { return bytes.ContainsAny(bs, chars.Std()) } 133 134 // ContainsRune checks if the Bytes contains the specified rune. 135 func (bs Bytes) ContainsRune(r rune) bool { return bytes.ContainsRune(bs, r) } 136 137 // Count counts the number of occurrences of the specified Bytes in the Bytes. 138 func (bs Bytes) Count(obs Bytes) Int { return Int(bytes.Count(bs, obs)) } 139 140 // Empty checks if the Bytes is empty. 141 func (bs Bytes) Empty() bool { return bs == nil || len(bs) == 0 } 142 143 // Eq checks if the Bytes is equal to another Bytes. 144 func (bs Bytes) Eq(obs Bytes) bool { return bs.Cmp(obs).IsEq() } 145 146 // EqFold compares two Bytes slices case-insensitively. 147 func (bs Bytes) EqFold(obs Bytes) bool { return bytes.EqualFold(bs, obs) } 148 149 // Gt checks if the Bytes is greater than another Bytes. 150 func (bs Bytes) Gt(obs Bytes) bool { return bs.Cmp(obs).IsGt() } 151 152 // ToString returns the Bytes as an String. 153 func (bs Bytes) ToString() String { return String(bs) } 154 155 // Index returns the index of the first instance of obs in bs, or -1 if bs is not present in obs. 156 func (bs Bytes) Index(obs Bytes) Int { return Int(bytes.Index(bs, obs)) } 157 158 // IndexRegexp searches for the first occurrence of the regular expression pattern in the Bytes. 159 // If a match is found, it returns an Option containing an Slice with the start and end indices of the match. 160 // If no match is found, it returns None. 161 func (bs Bytes) IndexRegexp(pattern *regexp.Regexp) Option[Slice[Int]] { 162 result := SliceMap(pattern.FindIndex(bs), NewInt) 163 if result.Empty() { 164 return None[Slice[Int]]() 165 } 166 167 return Some(result) 168 } 169 170 // FindAllRegexp searches the Bytes for all occurrences of the regular expression pattern 171 // and returns an Option[Slice[Bytes]] containing a slice of matched substrings. 172 // If no matches are found, the Option[Slice[Bytes]] will be None. 173 func (bs Bytes) FindAllRegexp(pattern *regexp.Regexp) Option[Slice[Bytes]] { 174 return bs.FindAllRegexpN(pattern, -1) 175 } 176 177 // FindAllRegexpN searches the Bytes for up to n occurrences of the regular expression pattern 178 // and returns an Option[Slice[Bytes]] containing a slice of matched substrings. 179 // If no matches are found, the Option[Slice[Bytes]] will be None. 180 // If n is negative, all occurrences will be returned. 181 func (bs Bytes) FindAllRegexpN(pattern *regexp.Regexp, n Int) Option[Slice[Bytes]] { 182 result := SliceMap(pattern.FindAll(bs, n.Std()), NewBytes) 183 if result.Empty() { 184 return None[Slice[Bytes]]() 185 } 186 187 return Some(result) 188 } 189 190 // FindSubmatchRegexp searches the Bytes for the first occurrence of the regular expression pattern 191 // and returns an Option[Slice[Bytes]] containing the matched substrings and submatches. 192 // The Option[Slice[Bytes]] will contain an Slice[Bytes] for each match, 193 // where each Slice[Bytes] will contain the full match at index 0, followed by any captured submatches. 194 // If no match is found, the Option[Slice[Bytes]] will be None. 195 func (bs Bytes) FindSubmatchRegexp(pattern *regexp.Regexp) Option[Slice[Bytes]] { 196 result := SliceMap(pattern.FindSubmatch(bs), NewBytes) 197 if result.Empty() { 198 return None[Slice[Bytes]]() 199 } 200 201 return Some(result) 202 } 203 204 // FindAllSubmatchRegexp searches the Bytes for all occurrences of the regular expression pattern 205 // and returns an Option[Slice[Slice[Bytes]]] containing the matched substrings and submatches. 206 // The Option[Slice[Slice[Bytes]]] will contain an Slice[Bytes] for each match, 207 // where each Slice[Bytes] will contain the full match at index 0, followed by any captured submatches. 208 // If no match is found, the Option[Slice[Slice[Bytes]]] will be None. 209 // This method is equivalent to calling SubmatchAllRegexpN with n = -1, which means it finds all occurrences. 210 func (bs Bytes) FindAllSubmatchRegexp(pattern *regexp.Regexp) Option[Slice[Slice[Bytes]]] { 211 return bs.FindAllSubmatchRegexpN(pattern, -1) 212 } 213 214 // FindAllSubmatchRegexpN searches the Bytes for occurrences of the regular expression pattern 215 // and returns an Option[Slice[Slice[Bytes]]] containing the matched substrings and submatches. 216 // The Option[Slice[Slice[Bytes]]] will contain an Slice[Bytes] for each match, 217 // where each Slice[Bytes] will contain the full match at index 0, followed by any captured submatches. 218 // If no match is found, the Option[Slice[Slice[Bytes]]] will be None. 219 // The 'n' parameter specifies the maximum number of matches to find. If n is negative, it finds all occurrences. 220 func (bs Bytes) FindAllSubmatchRegexpN(pattern *regexp.Regexp, n Int) Option[Slice[Slice[Bytes]]] { 221 var result Slice[Slice[Bytes]] 222 223 for _, v := range pattern.FindAllSubmatch(bs, n.Std()) { 224 result = append(result, SliceMap(v, NewBytes)) 225 } 226 227 if result.Empty() { 228 return None[Slice[Slice[Bytes]]]() 229 } 230 231 return Some(result) 232 } 233 234 // LastIndex returns the index of the last instance of obs in bs, or -1 if obs is not present in bs. 235 func (bs Bytes) LastIndex(obs Bytes) Int { return Int(bytes.LastIndex(bs, obs)) } 236 237 // IndexByte returns the index of the first instance of the byte b in bs, or -1 if b is not 238 // present in bs. 239 func (bs Bytes) IndexByte(b byte) Int { return Int(bytes.IndexByte(bs, b)) } 240 241 // LastIndexByte returns the index of the last instance of the byte b in bs, or -1 if b is not 242 // present in bs. 243 func (bs Bytes) LastIndexByte(b byte) Int { return Int(bytes.LastIndexByte(bs, b)) } 244 245 // IndexRune returns the index of the first instance of the rune r in bs, or -1 if r is not 246 // present in bs. 247 func (bs Bytes) IndexRune(r rune) Int { return Int(bytes.IndexRune(bs, r)) } 248 249 // Len returns the length of the Bytes. 250 func (bs Bytes) Len() Int { return Int(len(bs)) } 251 252 // LenRunes returns the number of runes in the Bytes. 253 func (bs Bytes) LenRunes() Int { return Int(utf8.RuneCount(bs)) } 254 255 // Lt checks if the Bytes is less than another Bytes. 256 func (bs Bytes) Lt(obs Bytes) bool { return bs.Cmp(obs).IsLt() } 257 258 // Map applies a function to each rune in the Bytes and returns the modified Bytes. 259 func (bs Bytes) Map(fn func(rune) rune) Bytes { return bytes.Map(fn, bs) } 260 261 // NormalizeNFC returns a new Bytes with its Unicode characters normalized using the NFC form. 262 func (bs Bytes) NormalizeNFC() Bytes { return norm.NFC.Bytes(bs) } 263 264 // Ne checks if the Bytes is not equal to another Bytes. 265 func (bs Bytes) Ne(obs Bytes) bool { return !bs.Eq(obs) } 266 267 // NotEmpty checks if the Bytes is not empty. 268 func (bs Bytes) NotEmpty() bool { return !bs.Empty() } 269 270 // Reader returns a *bytes.Reader initialized with the content of Bytes. 271 func (bs Bytes) Reader() *bytes.Reader { return bytes.NewReader(bs) } 272 273 // Repeat returns a new Bytes consisting of the current Bytes repeated 'count' times. 274 func (bs Bytes) Repeat(count Int) Bytes { return bytes.Repeat(bs, count.Std()) } 275 276 // ToRunes returns the Bytes as a slice of runes. 277 func (bs Bytes) ToRunes() []rune { return bytes.Runes(bs) } 278 279 // Title converts the Bytes to title case. 280 func (bs Bytes) Title() Bytes { return cases.Title(language.English).Bytes(bs) } 281 282 // Lower converts the Bytes to lowercase. 283 func (bs Bytes) Lower() Bytes { return cases.Lower(language.English).Bytes(bs) } 284 285 // Upper converts the Bytes to uppercase. 286 func (bs Bytes) Upper() Bytes { return cases.Upper(language.English).Bytes(bs) } 287 288 // TrimSpace trims white space characters from the beginning and end of the Bytes. 289 func (bs Bytes) TrimSpace() Bytes { return bytes.TrimSpace(bs) } 290 291 // Print prints the content of the Bytes to the standard output (console) 292 // and returns the Bytes unchanged. 293 func (bs Bytes) Print() Bytes { fmt.Println(bs); return bs }