| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 |
- // Copyright (c) Tailscale Inc & contributors
- // SPDX-License-Identifier: BSD-3-Clause
- // Package stringsx provides additional string manipulation functions
- // that aren't in the standard library's strings package or go4.org/mem.
- package stringsx
- import (
- "unicode"
- "unicode/utf8"
- )
- // CompareFold returns -1, 0, or 1 depending on whether a < b, a == b, or a > b,
- // like cmp.Compare, but case insensitively.
- func CompareFold(a, b string) int {
- // Track our position in both strings
- ia, ib := 0, 0
- for ia < len(a) && ib < len(b) {
- ra, wa := nextRuneLower(a[ia:])
- rb, wb := nextRuneLower(b[ib:])
- if ra < rb {
- return -1
- }
- if ra > rb {
- return 1
- }
- ia += wa
- ib += wb
- if wa == 0 || wb == 0 {
- break
- }
- }
- // If we've reached here, one or both strings are exhausted
- // The shorter string is "less than" if they match up to this point
- switch {
- case ia == len(a) && ib == len(b):
- return 0
- case ia == len(a):
- return -1
- default:
- return 1
- }
- }
- // nextRuneLower returns the next rune in the string, lowercased, along with its
- // original (consumed) width in bytes. If the string is empty, it returns
- // (utf8.RuneError, 0)
- func nextRuneLower(s string) (r rune, width int) {
- r, width = utf8.DecodeRuneInString(s)
- return unicode.ToLower(r), width
- }
|