mirror of https://github.com/golang/go.git
149 lines
3.6 KiB
Go
149 lines
3.6 KiB
Go
// Copyright 2024 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
|
|
|
|
import (
|
|
"iter"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// Lines returns an iterator over the newline-terminated lines in the string s.
|
|
// The lines yielded by the iterator include their terminating newlines.
|
|
// If s is empty, the iterator yields no lines at all.
|
|
// If s does not end in a newline, the final yielded line will not end in a newline.
|
|
// It returns a single-use iterator.
|
|
func Lines(s string) iter.Seq[string] {
|
|
return func(yield func(string) bool) {
|
|
for len(s) > 0 {
|
|
var line string
|
|
if i := IndexByte(s, '\n'); i >= 0 {
|
|
line, s = s[:i+1], s[i+1:]
|
|
} else {
|
|
line, s = s, ""
|
|
}
|
|
if !yield(line) {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
// explodeSeq returns an iterator over the runes in s.
|
|
func explodeSeq(s string) iter.Seq[string] {
|
|
return func(yield func(string) bool) {
|
|
for len(s) > 0 {
|
|
_, size := utf8.DecodeRuneInString(s)
|
|
if !yield(s[:size]) {
|
|
return
|
|
}
|
|
s = s[size:]
|
|
}
|
|
}
|
|
}
|
|
|
|
// splitSeq is SplitSeq or SplitAfterSeq, configured by how many
|
|
// bytes of sep to include in the results (none or all).
|
|
func splitSeq(s, sep string, sepSave int) iter.Seq[string] {
|
|
if len(sep) == 0 {
|
|
return explodeSeq(s)
|
|
}
|
|
return func(yield func(string) bool) {
|
|
for {
|
|
i := Index(s, sep)
|
|
if i < 0 {
|
|
break
|
|
}
|
|
frag := s[:i+sepSave]
|
|
if !yield(frag) {
|
|
return
|
|
}
|
|
s = s[i+len(sep):]
|
|
}
|
|
yield(s)
|
|
}
|
|
}
|
|
|
|
// SplitSeq returns an iterator over all substrings of s separated by sep.
|
|
// The iterator yields the same strings that would be returned by Split(s, sep),
|
|
// but without constructing the slice.
|
|
// It returns a single-use iterator.
|
|
func SplitSeq(s, sep string) iter.Seq[string] {
|
|
return splitSeq(s, sep, 0)
|
|
}
|
|
|
|
// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep.
|
|
// The iterator yields the same strings that would be returned by SplitAfter(s, sep),
|
|
// but without constructing the slice.
|
|
// It returns a single-use iterator.
|
|
func SplitAfterSeq(s, sep string) iter.Seq[string] {
|
|
return splitSeq(s, sep, len(sep))
|
|
}
|
|
|
|
// FieldsSeq returns an iterator over substrings of s split around runs of
|
|
// whitespace characters, as defined by unicode.IsSpace.
|
|
// The iterator yields the same strings that would be returned by Fields(s),
|
|
// but without constructing the slice.
|
|
func FieldsSeq(s string) iter.Seq[string] {
|
|
return func(yield func(string) bool) {
|
|
start := -1
|
|
for i := 0; i < len(s); {
|
|
size := 1
|
|
r := rune(s[i])
|
|
isSpace := asciiSpace[s[i]] != 0
|
|
if r >= utf8.RuneSelf {
|
|
r, size = utf8.DecodeRuneInString(s[i:])
|
|
isSpace = unicode.IsSpace(r)
|
|
}
|
|
if isSpace {
|
|
if start >= 0 {
|
|
if !yield(s[start:i]) {
|
|
return
|
|
}
|
|
start = -1
|
|
}
|
|
} else if start < 0 {
|
|
start = i
|
|
}
|
|
i += size
|
|
}
|
|
if start >= 0 {
|
|
yield(s[start:])
|
|
}
|
|
}
|
|
}
|
|
|
|
// FieldsFuncSeq returns an iterator over substrings of s split around runs of
|
|
// Unicode code points satisfying f(c).
|
|
// The iterator yields the same strings that would be returned by FieldsFunc(s),
|
|
// but without constructing the slice.
|
|
func FieldsFuncSeq(s string, f func(rune) bool) iter.Seq[string] {
|
|
return func(yield func(string) bool) {
|
|
start := -1
|
|
for i := 0; i < len(s); {
|
|
size := 1
|
|
r := rune(s[i])
|
|
if r >= utf8.RuneSelf {
|
|
r, size = utf8.DecodeRuneInString(s[i:])
|
|
}
|
|
if f(r) {
|
|
if start >= 0 {
|
|
if !yield(s[start:i]) {
|
|
return
|
|
}
|
|
start = -1
|
|
}
|
|
} else if start < 0 {
|
|
start = i
|
|
}
|
|
i += size
|
|
}
|
|
if start >= 0 {
|
|
yield(s[start:])
|
|
}
|
|
}
|
|
}
|