@@ -63,7 +63,7 @@ export const urljoin = (fromPath, nowPath) => {
63
63
export const urljoin2 = urljoin
64
64
export const joinUrl = urljoin
65
65
66
-
66
+ /*
67
67
export function naturalSort(arr, key, customOrder = []) {
68
68
return arr.sort((a, b) => {
69
69
const aValue = a[key];
@@ -88,3 +88,101 @@ export function naturalSort(arr, key, customOrder = []) {
88
88
return aValue.localeCompare(bValue, undefined, {numeric: true, sensitivity: 'base'});
89
89
});
90
90
}
91
+ */
92
+
93
+ export function naturalSort ( arr , key , customOrder = [ ] ) {
94
+ const collator = new Intl . Collator ( 'zh-Hans-CN' , {
95
+ numeric : true ,
96
+ sensitivity : 'base' ,
97
+ } ) ;
98
+
99
+ return arr . sort ( ( a , b ) => {
100
+ const x = a [ key ] || '' ;
101
+ const y = b [ key ] || '' ;
102
+
103
+ // 1. 检查自定义顺序
104
+ const xIndex = customOrder . findIndex ( ( item ) => x . startsWith ( item ) ) ;
105
+ const yIndex = customOrder . findIndex ( ( item ) => y . startsWith ( item ) ) ;
106
+
107
+ if ( xIndex !== - 1 || yIndex !== - 1 ) {
108
+ if ( xIndex === - 1 ) return 1 ; // x 不在自定义顺序中,y 在
109
+ if ( yIndex === - 1 ) return - 1 ; // y 不在自定义顺序中,x 在
110
+ return xIndex - yIndex ; // 两者都在自定义顺序中,按索引排序
111
+ }
112
+
113
+ // 2. 使用 `Intl.Collator` 进行自然排序
114
+ return collator . compare ( x , y ) ;
115
+ } ) ;
116
+ }
117
+
118
+ export function naturalSortAny ( arr , key , customOrder = [ ] ) {
119
+ return arr . sort ( ( a , b ) => {
120
+ const EQUAL = 0 ;
121
+ const GREATER = 1 ;
122
+ const SMALLER = - 1 ;
123
+
124
+ const options = { caseSensitive : false } ;
125
+
126
+ const re = / ( ^ - ? [ 0 - 9 ] + ( \. ? [ 0 - 9 ] * ) [ d f ] ? e ? [ 0 - 9 ] ? $ | ^ 0 x [ 0 - 9 a - f ] + $ | [ 0 - 9 ] + ) / gi;
127
+ const sre = / ( ^ [ ] * | [ ] * $ ) / g;
128
+ const dre = / ( ^ ( [ \w ] + , ? [ \w ] + ) ? [ \w ] + , ? [ \w ] + \d + : \d + ( : \d + ) ? [ \w ] ? | ^ \d { 1 , 4 } [ \/ \- ] \d { 1 , 4 } [ \/ \- ] \d { 1 , 4 } | ^ \w + , \w + \d + , \d { 4 } ) / ;
129
+ const hre = / ^ 0 x [ 0 - 9 a - f ] + $ / i;
130
+ const ore = / ^ 0 / ;
131
+
132
+ const normalize = function normalize ( value ) {
133
+ const string = '' + value ;
134
+ return options . caseSensitive ? string : string . toLowerCase ( ) ;
135
+ } ;
136
+
137
+ const x = normalize ( a [ key ] ) . replace ( sre , '' ) || '' ;
138
+ const y = normalize ( b [ key ] ) . replace ( sre , '' ) || '' ;
139
+
140
+ // Check custom order first
141
+ const xIndex = customOrder . findIndex ( ( item ) => x . startsWith ( item ) ) ;
142
+ const yIndex = customOrder . findIndex ( ( item ) => y . startsWith ( item ) ) ;
143
+
144
+ if ( xIndex !== - 1 || yIndex !== - 1 ) {
145
+ if ( xIndex === - 1 ) return GREATER ; // x not in customOrder, y is
146
+ if ( yIndex === - 1 ) return SMALLER ; // y not in customOrder, x is
147
+ return xIndex - yIndex ; // Both in customOrder, compare their indices
148
+ }
149
+
150
+ // chunk/tokenize
151
+ const xN = x . replace ( re , '\0$1\0' ) . replace ( / \0 $ / , '' ) . replace ( / ^ \0 / , '' ) . split ( '\0' ) ;
152
+ const yN = y . replace ( re , '\0$1\0' ) . replace ( / \0 $ / , '' ) . replace ( / ^ \0 / , '' ) . split ( '\0' ) ;
153
+
154
+ // Return immediately if at least one of the values is empty.
155
+ if ( ! x && ! y ) return EQUAL ;
156
+ if ( ! x && y ) return GREATER ;
157
+ if ( x && ! y ) return SMALLER ;
158
+
159
+ // numeric, hex or date detection
160
+ const xD = parseInt ( x . match ( hre ) ) || ( xN . length != 1 && x . match ( dre ) && Date . parse ( x ) ) ;
161
+ const yD = parseInt ( y . match ( hre ) ) || ( xD && y . match ( dre ) && Date . parse ( y ) ) || null ;
162
+ let oFxNcL , oFyNcL ;
163
+
164
+ // first try and sort Hex codes or Dates
165
+ if ( yD ) {
166
+ if ( xD < yD ) return SMALLER ;
167
+ else if ( xD > yD ) return GREATER ;
168
+ }
169
+
170
+ // natural sorting through split numeric strings and default strings
171
+ for ( let cLoc = 0 , numS = Math . max ( xN . length , yN . length ) ; cLoc < numS ; cLoc ++ ) {
172
+ oFxNcL = ! ( xN [ cLoc ] || '' ) . match ( ore ) && parseFloat ( xN [ cLoc ] ) || xN [ cLoc ] || 0 ;
173
+ oFyNcL = ! ( yN [ cLoc ] || '' ) . match ( ore ) && parseFloat ( yN [ cLoc ] ) || yN [ cLoc ] || 0 ;
174
+
175
+ // handle numeric vs string comparison - number < string - (Kyle Adams)
176
+ if ( isNaN ( oFxNcL ) !== isNaN ( oFyNcL ) ) return isNaN ( oFxNcL ) ? GREATER : SMALLER ;
177
+
178
+ // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
179
+ else if ( typeof oFxNcL !== typeof oFyNcL ) {
180
+ oFxNcL += '' ;
181
+ oFyNcL += '' ;
182
+ }
183
+ if ( oFxNcL < oFyNcL ) return SMALLER ;
184
+ if ( oFxNcL > oFyNcL ) return GREATER ;
185
+ }
186
+ return EQUAL ;
187
+ } ) ;
188
+ }
0 commit comments