avoid memory allocations in natural sorting

This commit is contained in:
Gokcehan 2020-11-06 15:14:38 +03:00
parent f877960661
commit 24489924b7

47
misc.go
View File

@ -166,32 +166,45 @@ func humanize(size int64) string {
return "" return ""
} }
// This regexp is used to partition a given string as numbers and non-numbers. // This function compares two strings for natural sorting which takes into
// For instance, if your input is 'foo123bar456' you get a slice of 'foo', // account values of numbers in strings. For example, '2' is less than '10',
// '123', 'bar', and '456'. This is useful for natural sorting which takes into // and similarly 'foo2bar' is less than 'foo10bar', but 'bar2bar' is greater
// account values of numbers within strings. // than 'foo10bar'.
var rePart = regexp.MustCompile(`\d+|\D+`)
func naturalLess(s1, s2 string) bool { func naturalLess(s1, s2 string) bool {
parts1 := rePart.FindAllString(s1, -1) lo1, lo2, hi1, hi2 := 0, 0, 0, 0
parts2 := rePart.FindAllString(s2, -1) for {
if hi1 >= len(s1) {
return hi2 != len(s2)
}
for i := 0; i < len(parts1) && i < len(parts2); i++ { if hi2 >= len(s2) {
if parts1[i] == parts2[i] { return false
}
isDigit1 := isDigit(s1[hi1])
isDigit2 := isDigit(s2[hi2])
for lo1 = hi1; hi1 < len(s1) && isDigit(s1[hi1]) == isDigit1; hi1++ {
}
for lo2 = hi2; hi2 < len(s2) && isDigit(s2[hi2]) == isDigit2; hi2++ {
}
if s1[lo1:hi1] == s2[lo2:hi2] {
continue continue
} }
num1, err1 := strconv.Atoi(parts1[i]) if isDigit1 && isDigit2 {
num2, err2 := strconv.Atoi(parts2[i]) num1, err1 := strconv.Atoi(s1[lo1:hi1])
num2, err2 := strconv.Atoi(s2[lo2:hi2])
if err1 == nil && err2 == nil { if err1 == nil && err2 == nil {
return num1 < num2 return num1 < num2
}
} }
return parts1[i] < parts2[i] return s1[lo1:hi1] < s2[lo2:hi2]
} }
return len(parts1) < len(parts2)
} }
var reAltKey = regexp.MustCompile(`<a-(.)>`) var reAltKey = regexp.MustCompile(`<a-(.)>`)