// Copyright 2026 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 sgutil import ( "strconv" "strings" ) // isDigit returns true if the byte is an ASCII digit. func isDigit(b byte) bool { return b >= '0' && b <= '9' } // CompareNatural performs a "natural sort" comparison of two strings. // It compares non-digit sections lexicographically and digit sections // numerically. In the case of string-unequal "equal" strings like // "a01b" and "a1b", strings.Compare breaks the tie. // // It returns: // // -1 if s1 < s2 // 0 if s1 == s2 // +1 if s1 > s2 func CompareNatural(s1, s2 string) int { i, j := 0, 0 len1, len2 := len(s1), len(s2) for i < len1 && j < len2 { // Find a non-digit segment or a number segment in both strings. if isDigit(s1[i]) && isDigit(s2[j]) { // Number segment comparison. numStart1 := i for i < len1 && isDigit(s1[i]) { i++ } num1, _ := strconv.Atoi(s1[numStart1:i]) numStart2 := j for j < len2 && isDigit(s2[j]) { j++ } num2, _ := strconv.Atoi(s2[numStart2:j]) if num1 < num2 { return -1 } if num1 > num2 { return 1 } // "1" < "01". Don't expect it in simdgen, but just in case. if ln1, ln2 := i-numStart1, j-numStart2; ln1 != ln2 { return ln1 - ln2 } // If numbers are equal, continue to the next segment. } else { // Non-digit comparison. if s1[i] < s2[j] { return -1 } if s1[i] > s2[j] { return 1 } i++ j++ } } // deal with a01b vs a1b; there needs to be an order. return strings.Compare(s1, s2) }