Proposal Details
There are some situations where it's desirable to split a string at some known size but avoid splitting UTF-8 sequences. Examples include truncating a string to a limited length when logging, and doing character-oriented manipulation within an io.Reader.
Currently the easiest way to do that is by traversing from the start of the string, decoding runes until the desired split point is reached, but this is unnecessarily inefficient.
Getting this right is surprisingly tricky.
I propose we add two new functions to unicode/utf8:
// LastPartialRuneLen returns the number of bytes at the
// end of p that might be the start of a valid UTF-8 byte
// sequence.
func LastPartialRuneLen(p []byte) int
// LastPartialRuneLenInString is like LastPartialRuneLen
// but for strings.
func LastPartialRuneLenInString(s string) int
Here's a possible implementation, very lightly tested as yet:
func LastPartialRune[T ~[]byte|~string](p T) int {
end := len(p)
if end == 0 {
return 0
}
start := end - 1
lim := max(0, end-utf8.UTFMax)
for ; start >= lim; start-- {
r := p[start]
if r < utf8.RuneSelf {
return 0
}
if r&0b1100_0000 == 0b1000_0000 {
// continuation byte.
continue
}
if r, size := utf8.DecodeRune(p[start:]); r != utf8.RuneError || size > 1 {
return 0
}
return end - start
}
// It's all continuation characters up to here.
// They can't _all_ be continuation characters:
// the last one definitely isn't, so we can't consider
// it a partial rune.
return 0
}
It might be nice to add it as a generic function that works on []byte and string, but that would need a generic version of DecodeRune too.
Proposal Details
There are some situations where it's desirable to split a string at some known size but avoid splitting UTF-8 sequences. Examples include truncating a string to a limited length when logging, and doing character-oriented manipulation within an
io.Reader.Currently the easiest way to do that is by traversing from the start of the string, decoding runes until the desired split point is reached, but this is unnecessarily inefficient.
Getting this right is surprisingly tricky.
I propose we add two new functions to
unicode/utf8:Here's a possible implementation, very lightly tested as yet:
It might be nice to add it as a generic function that works on []byte and string, but that would need a generic version of DecodeRune too.