🐙
文字列ソートで数字が含まれている箇所は数値で比較する方法
ソフトウェアのバージョン番号(e.g. 1.9.5
, 1.10.2
)やファイル名(e.g. Mobile Mission Part1.m4a
, Mobile Mission Part2.m4a
)など文字列の中に数字が含まれていることは少なくないです。
しかしながら、文字列としてソート(辞書順ソート)してしまうと少し不便な並び順になってしまいます。
例えば、通し番号のついたファイルの場合は通常以下のように並ぶと思います。
- File_1
- File_10
- File_2
- File_3
- File_4
- File_5
- File_6
- File_7
- File_8
- File_9
直感的には、次のような順序の方がわかりやすいでしょう。
- File_1
- File_2
- File_3
- File_4
- File_5
- File_6
- File_7
- File_8
- File_9
- File_10
さらにFile_2_2
のように枝番があったり、FileB (2-2 ver)
のように書式の異なるファイル群があったりするなど、ファイル名のどこに数字が現れるか明確でないと処理するのが厄介に思えます。
しかし、とにかく「文字列のどこかに現れる数字は数値としてソートする」というルールであれば下記の方法でソートできます。
sort.ts
const compare = ( a: string, b: string ): number => {
if ( a === b ) return 0
const [ $a, $b ] = [ a, b ].map(
text => text.match( /(\d+|\D+)/g )!.map(
str => /^\d+$/.test( str ) ? parseInt( str, 10 ) : str
)
)
const length = Math.min( $a.length, $b.length )
for ( let i = 0; i < length; ++ i ) {
const [ x, y ] = [ $a[ i ], $b[ i ] ]
if ( x !== y ) { return x < y ? -1 : 1 }
}
return $a.length < $b.length ? -1 : 1
}
const list = Array( 10 ).fill( "File_" ).map( ( prefix, index ) => `${ prefix }${ index + 1 }` )
//望まないソート
console.log( list.sort() )
//望みのソート
console.log( list.sort( compare ) )
以上!
ぜひお試しください。
Discussion