|
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