-
Notifications
You must be signed in to change notification settings - Fork 159
/
Copy pathnatsort.js
83 lines (67 loc) · 3.24 KB
/
natsort.js
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
/**
* ESM Module: Natural Compare Function
*/
function naturalCompareFactory(options) {
function splitString(str) {
return str
.replace(tokenRegex, "\0$1\0")
.replace(/\0$/, "")
.replace(/^\0/, "")
.split("\0");
}
function parseToken(token, length) {
return (!token.match(leadingZeroRegex) || length === 1) && parseFloat(token) ||
token.replace(whitespaceRegex, " ").replace(trimRegex, "") ||
0;
}
options = options || {};
const leadingZeroRegex = /^0/,
whitespaceRegex = /\s+/g,
trimRegex = /^\s+|\s+$/g,
unicodeRegex = /[^\x00-\x80]/,
hexRegex = /^0x[0-9a-f]+$/i,
tokenRegex = /(0x[\da-fA-F]+|(^[\+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|\d+)/g,
dateRegex = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
toLowerCase = String.prototype.toLocaleLowerCase || String.prototype.toLowerCase,
ascending = options.desc ? -1 : 1,
descending = -ascending,
preprocess = options.insensitive
? (str) => toLowerCase.call("" + str).replace(trimRegex, "")
: (str) => ("" + str).replace(trimRegex, "");
return function compareStrings(a, b) {
const strA = preprocess(a);
const strB = preprocess(b);
if (!strA && !strB) return 0;
if (!strA && strB) return descending;
if (strA && !strB) return ascending;
const tokensA = splitString(strA);
const tokensB = splitString(strB);
const hexMatchA = strA.match(hexRegex);
const hexMatchB = strB.match(hexRegex);
const parsedDateA = hexMatchA && hexMatchB ? parseInt(hexMatchA[0], 16) : tokensA.length > 1 ? Date.parse(strA) : null;
const parsedDateB = hexMatchA && hexMatchB ? parseInt(hexMatchB[0], 16) : parsedDateA && strB.match(dateRegex) ? Date.parse(strB) : null;
if (parsedDateA && parsedDateB) {
if (parsedDateA === parsedDateB) return 0;
return parsedDateA < parsedDateB ? descending : ascending;
}
const maxTokens = Math.max(tokensA.length, tokensB.length);
for (let i = 0; i < maxTokens; i++) {
const tokenA = parseToken(tokensA[i] || "", tokensA.length);
const tokenB = parseToken(tokensB[i] || "", tokensB.length);
if (isNaN(tokenA) !== isNaN(tokenB)) return isNaN(tokenA) ? ascending : descending;
if (unicodeRegex.test(tokenA + tokenB) && tokenA.localeCompare) {
// const localeComparison = tokenA.localeCompare(tokenB);
const localeComparison = tokenA.localeCompare(tokenB, 'zh-CN', {numeric: true, sensitivity: 'base'});
if (localeComparison !== 0) return localeComparison * ascending;
}
if (tokenA < tokenB) return descending;
if (tokenA > tokenB) return ascending;
if ("" + tokenA < "" + tokenB) return descending;
if ("" + tokenA > "" + tokenB) return ascending;
}
return 0;
};
}
export default naturalCompareFactory;
// 使用工厂函数创建比较器
export const naturalCompare = naturalCompareFactory({desc: false, insensitive: true});