@@ -169,16 +169,6 @@ export function getParentPath(path = getRoutePath()) {
169169}
170170
171171
172- function extractNumber ( str , start ) {
173- let result = 0 ;
174- let i = start ;
175- while ( i < str . length && / \d / . test ( str [ i ] ) ) {
176- result = result * 10 + ( str . charCodeAt ( i ) - 48 ) ;
177- i ++ ;
178- }
179- return result ;
180- }
181-
182172export function deepEqual ( a , b ) {
183173 // 基本类型和引用类型直接比较
184174 if ( a === b ) return true ;
@@ -199,21 +189,78 @@ export function deepEqual(a, b) {
199189 return aKeys . every ( key => b . hasOwnProperty ( key ) && deepEqual ( a [ key ] , b [ key ] ) ) ;
200190}
201191
192+ /**
193+ * 优化后的 Windows 文件名自然排序算法
194+ */
202195export function compareByName ( a , b ) {
203- let i1 = 0 , i2 = 0 ;
204- while ( i1 < a . length && i2 < b . length ) {
205- if ( / \d / . test ( a [ i1 ] ) && / \d / . test ( b [ i2 ] ) ) {
206- const n1 = extractNumber ( a , i1 ) ;
207- const n2 = extractNumber ( b , i2 ) ;
208- i1 += n1 . toString ( ) . length ;
209- i2 += n2 . toString ( ) . length ;
210- if ( n1 !== n2 ) return n1 - n2 ;
196+ if ( a === b ) return 0 ;
197+
198+ const len1 = a . length ;
199+ const len2 = b . length ;
200+ let i = 0 ;
201+ let j = 0 ;
202+
203+ while ( i < len1 && j < len2 ) {
204+ let c1 = a . charCodeAt ( i ) ;
205+ let c2 = b . charCodeAt ( j ) ;
206+
207+ // 判断是否为数字 (0-9)
208+ const isDig1 = c1 >= 48 && c1 <= 57 ;
209+ const isDig2 = c2 >= 48 && c2 <= 57 ;
210+
211+ if ( isDig1 && isDig2 ) {
212+ let start1 = i ;
213+ let start2 = j ;
214+
215+ // 跳过前导零,但保留最后一个零(如果是全零的情况)
216+ while ( i < len1 - 1 && a . charCodeAt ( i ) === 48 ) {
217+ const next = a . charCodeAt ( i + 1 ) ;
218+ if ( next < 48 || next > 57 ) break ;
219+ i ++ ;
220+ }
221+ while ( j < len2 - 1 && b . charCodeAt ( j ) === 48 ) {
222+ const next = b . charCodeAt ( j + 1 ) ;
223+ if ( next < 48 || next > 57 ) break ;
224+ j ++ ;
225+ }
226+
227+ let valStart1 = i ;
228+ let valStart2 = j ;
229+
230+ while ( i < len1 && ( c1 = a . charCodeAt ( i ) ) >= 48 && c1 <= 57 ) i ++ ;
231+ while ( j < len2 && ( c2 = b . charCodeAt ( j ) ) >= 48 && c2 <= 57 ) j ++ ;
232+
233+ const numLen1 = i - valStart1 ;
234+ const numLen2 = j - valStart2 ;
235+
236+ // 长度不同,数值大的字符串肯定长
237+ if ( numLen1 !== numLen2 ) return numLen1 - numLen2 ;
238+
239+ // 长度相同,逐位比较
240+ for ( let k = 0 ; k < numLen1 ; k ++ ) {
241+ const diff = a . charCodeAt ( valStart1 + k ) - b . charCodeAt ( valStart2 + k ) ;
242+ if ( diff !== 0 ) return diff ;
243+ }
244+
245+ // 数值完全一样,比较含前导零的原始长度 (短的在前)
246+ const fullLen1 = i - start1 ;
247+ const fullLen2 = j - start2 ;
248+ if ( fullLen1 !== fullLen2 ) return fullLen1 - fullLen2 ;
249+
211250 } else {
212- if ( a [ i1 ] !== b [ i2 ] ) return a [ i1 ] . charCodeAt ( 0 ) - b [ i2 ] . charCodeAt ( 0 ) ;
213- i1 ++ ;
214- i2 ++ ;
251+ if ( c1 !== c2 ) {
252+ // 转小写比较 (仅限 A-Z)
253+ const low1 = ( c1 >= 65 && c1 <= 90 ) ? c1 + 32 : c1 ;
254+ const low2 = ( c2 >= 65 && c2 <= 90 ) ? c2 + 32 : c2 ;
255+
256+ if ( low1 !== low2 ) return low1 - low2 ;
257+ // 如果小写相同但原始码点不同(如 'a' vs 'A'),保持稳定排序
258+ return c1 - c2 ;
259+ }
260+ i ++ ;
261+ j ++ ;
215262 }
216263 }
217- return a . length - b . length ;
218- }
219264
265+ return len1 - len2 ;
266+ }
0 commit comments