目的
JavaScriptで日本語でのソートを行う際、意図した挙動にならなかったため自分なりに調べた結果をまとめました。
今回はこんな感じで単純な文字列をソートしていきます。
const array = ["う", "い", "あ", "ウ", "イ", "ア", "宇", "井", "亜", "a", "i", "u"];
ひらがな、カタカナ、漢字、英語が混じった配列ですね。
単純なソート関数
JavaScriptの組み込み関数であるsort関数を使う場合、以下のようになります。
const array = ["う", "い", "あ", "ウ", "イ", "ア", "宇", "井", "亜", "a", "i", "u"];
array.sort();
console.log(array);
// 出力結果 => [a,i,u,あ,い,う,ア,イ,ウ,井,亜,宇]
並び順が 英語 -> ひらがな -> カタカナ -> 漢字 となりました。
漢字に至っては50音順にすらなっていませんね。
sort( )を使用した場合、並び順は以下のようになる
英語 -> ひらがな -> カタカナ -> 漢字
ソートの順番について
ソートの順番がどのように決まるかの補足説明になります。
ドキュメントには以下のように記載されています。
ソート順を定義する関数を指定します。省略された場合、配列の各要素は文字列に変換され、各文字の Unicode コードポイント順に従ってソートされます。
ここで、それぞれの文字のUnicode コードポイントを確認してみましょう。
const array = ["う", "い", "あ", "ウ", "イ", "ア", "宇", "井", "亜", "a", "i", "u"];
const point = array.map(n => n.codePointAt())
console.log(point});
// 出力結果 => [12358,12356,12354,12454,12452,12450,23431,20117,20124,97,105,117]
つまり、sort関数では 英語 -> ひらがな -> カタカナ -> 漢字 と意図的にグルーピングされているというわけでなく、
単純にポイント順に並び替えが行われているということです。
sort( )を使用した場合、並び順はUnicodeコードポイント順となる
日本語に準じた50音順でソート
日本語の50音順にソートしたい場合はlocaleCompareやIntl.Collatorを利用します。
const array = ["う", "い", "あ", "ウ", "イ", "ア", "宇", "井", "亜", "a", "i", "u"];
array.sort((a, b) => {
return a.localeCompare(b, 'ja');
});
console.log(array);
// 出力結果 => [a,i,u,あ,ア,い,イ,う,ウ,亜,井,宇]
const array = ["う", "い", "あ", "ウ", "イ", "ア", "宇", "井", "亜", "a", "i", "u"];
const collator = new Intl.Collator("ja");
array.sort(collator.compare);
console.log(array);
// 出力結果 => [a,i,u,あ,ア,い,イ,う,ウ,亜,井,宇]
並び順がUnicodeコードポイント順ではなく、英語 -> ひらがな&カタカナ -> 漢字 順になりましたね。
sort( )を使用する際、localeCompareやIntl.Collatorを使うことによって
50音順に並べることができる
ホントに50音順といえるのか
ふと、50音順と言われた場合の出力結果が [a, i, u, あ, ア, い, イ, う, ウ, 亜, 井, 宇] で納得できるか疑問に思いました。
英語は別として、やはり私たちの日常生活では50音順と言われれば以下のような結果を予測しますよね。
- [あ, ア, 亜, い, イ, 井, う, ウ, 宇]
しかし漢字を含めた場合、そこまでの完璧なソートは無理なようです。
考えてみれば当たり前のことかもしれません。漢字には様々な「読み」が存在しますもんね。
(人名であればなおさら、同じ漢字なのに読みが異なる苗字なんて沢山ありますしね。。。)
もし、自分が思う読み通りのソートを行いたい場合、予め振り仮名属性を持たせておく必要があります。
なので、人名をソートしたい場合なんかも意図しない並びになることが多々あるかと思います。
const array = ["平田", "鈴木", "石井", "田中"];
// [石井(いしい), 鈴木(すずき), 田中(たなか), 平田(ひらた)] の順になってほしい
// sort関数
array.sort();
console.log(array);
// [平田,田中,石井,鈴木]
// localeCompare
array.sort((a, b) => {
return a.localeCompare(b, 'ja');
});
console.log(array)
// [石井,田中,平田,鈴木]
// Intl.Collator
const collator = new Intl.Collator("ja");
array.sort(collator.compare);
console.log(array)
// [石井,田中,平田,鈴木]
漢字を含む場合、思い通りに並び替えるのは難しい
漢字だけでなく振り仮名を持たせ、それをもとにソートを行うとよい
まとめ
ここまでで、sort( )の挙動を確認できました。
単純な数値や英語だけのソートならまだしも、日本語(ひらがな・カタカナ・漢字)を含めると意外と奥が深いことがわかりました。
ここら辺をさらに深ぼるには文字コードとか色々と関わってきそうですね。
今回はこの辺で。。。