|
4 | 4 | package base |
5 | 5 |
|
6 | 6 | import ( |
7 | | - "math/big" |
8 | | - "unicode/utf8" |
| 7 | + "golang.org/x/text/collate" |
| 8 | + "golang.org/x/text/language" |
9 | 9 | ) |
10 | 10 |
|
11 | 11 | // NaturalSortLess compares two strings so that they could be sorted in natural order |
12 | 12 | func NaturalSortLess(s1, s2 string) bool { |
13 | | - var i1, i2 int |
14 | | - for { |
15 | | - rune1, j1, end1 := getNextRune(s1, i1) |
16 | | - rune2, j2, end2 := getNextRune(s2, i2) |
17 | | - if end1 || end2 { |
18 | | - return end1 != end2 && end1 |
19 | | - } |
20 | | - dec1 := isDecimal(rune1) |
21 | | - dec2 := isDecimal(rune2) |
22 | | - var less, equal bool |
23 | | - if dec1 && dec2 { |
24 | | - i1, i2, less, equal = compareByNumbers(s1, i1, s2, i2) |
25 | | - } else if !dec1 && !dec2 { |
26 | | - equal = rune1 == rune2 |
27 | | - less = rune1 < rune2 |
28 | | - i1 = j1 |
29 | | - i2 = j2 |
30 | | - } else { |
31 | | - return rune1 < rune2 |
32 | | - } |
33 | | - if !equal { |
34 | | - return less |
35 | | - } |
36 | | - } |
37 | | -} |
38 | | - |
39 | | -func getNextRune(str string, pos int) (rune, int, bool) { |
40 | | - if pos < len(str) { |
41 | | - r, w := utf8.DecodeRuneInString(str[pos:]) |
42 | | - // Fallback to ascii |
43 | | - if r == utf8.RuneError { |
44 | | - r = rune(str[pos]) |
45 | | - w = 1 |
46 | | - } |
47 | | - return r, pos + w, false |
48 | | - } |
49 | | - return 0, pos, true |
50 | | -} |
51 | | - |
52 | | -func isDecimal(r rune) bool { |
53 | | - return '0' <= r && r <= '9' |
54 | | -} |
55 | | - |
56 | | -func compareByNumbers(str1 string, pos1 int, str2 string, pos2 int) (i1, i2 int, less, equal bool) { |
57 | | - d1, d2 := true, true |
58 | | - var dec1, dec2 string |
59 | | - for d1 || d2 { |
60 | | - if d1 { |
61 | | - r, j, end := getNextRune(str1, pos1) |
62 | | - if !end && isDecimal(r) { |
63 | | - dec1 += string(r) |
64 | | - pos1 = j |
65 | | - } else { |
66 | | - d1 = false |
67 | | - } |
68 | | - } |
69 | | - if d2 { |
70 | | - r, j, end := getNextRune(str2, pos2) |
71 | | - if !end && isDecimal(r) { |
72 | | - dec2 += string(r) |
73 | | - pos2 = j |
74 | | - } else { |
75 | | - d2 = false |
76 | | - } |
77 | | - } |
78 | | - } |
79 | | - less, equal = compareBigNumbers(dec1, dec2) |
80 | | - return pos1, pos2, less, equal |
81 | | -} |
82 | | - |
83 | | -func compareBigNumbers(dec1, dec2 string) (less, equal bool) { |
84 | | - d1, _ := big.NewInt(0).SetString(dec1, 10) |
85 | | - d2, _ := big.NewInt(0).SetString(dec2, 10) |
86 | | - cmp := d1.Cmp(d2) |
87 | | - return cmp < 0, cmp == 0 |
| 13 | + c := collate.New(language.English, collate.Numeric) |
| 14 | + return c.CompareString(s1, s2) < 0 |
88 | 15 | } |
0 commit comments