1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
// Package natsort implements natural strings sorting
package natsort
import (
"regexp"
"sort"
"strconv"
"strings"
)
// IgnoreCase ignores cases
var IgnoreCase = false
type stringSlice []string
func (s stringSlice) Len() int {
return len(s)
}
func (s stringSlice) Less(a, b int) bool {
return Compare(s[a], s[b], IgnoreCase)
}
func (s stringSlice) Swap(a, b int) {
s[a], s[b] = s[b], s[a]
}
func chunkify(s string) []string {
re, _ := regexp.Compile(`(\d+|\D+)`)
return re.FindAllString(s, -1)
}
// Sort sorts a list of strings in a natural order
func Sort(l []string) {
sort.Sort(stringSlice(l))
}
// Compare returns true if the first string precedes the second one according to natural order
func Compare(a, b string, ignoreCase bool) bool {
if a == "" {
return true
} else if b == "" {
return false
}
if ignoreCase {
a = strings.ToLower(a)
b = strings.ToLower(b)
}
chunksA := chunkify(a)
chunksB := chunkify(b)
nChunksA := len(chunksA)
nChunksB := len(chunksB)
for i := range chunksA {
aInt, aErr := strconv.Atoi(chunksA[i])
bInt, bErr := strconv.Atoi(chunksB[i])
// If both chunks are numeric, compare them as integers
if aErr == nil && bErr == nil {
if aInt == bInt {
if i == nChunksA-1 {
// We reached the last chunk of A, thus B is greater than A
return true
} else if i == nChunksB-1 {
// We reached the last chunk of B, thus A is greater than B
return false
}
continue
}
return aInt < bInt
}
// So far both strings are equal, continue to next chunk
if chunksA[i] == chunksB[i] {
if i == nChunksA-1 {
// We reached the last chunk of A, thus B is greater than A
return true
} else if i == nChunksB-1 {
// We reached the last chunk of B, thus A is greater than B
return false
}
continue
}
return chunksA[i] < chunksB[i]
}
return false
}
|