Loading
  • LIGHT

  • DARK

ROUTE

ルートゼロの
アクティビティ

JavaScript文字列比較・日本語ソート完全ガイド|実務で使える5つの方法

3

はじめに|この記事で得られる価値

「JavaScriptで五十音順に並べたはずなのに、順番がバラバラ……」
そんな場面で焦った経験はありませんか?

私たちも、一覧画面のソート実装で
同じ壁にぶつかることがあります。

この記事では、日本語特有の並び順の難しさを整理しながら、
実務でそのまま使いやすい比較方法を解説します。

特に押さえたいのは、次の3点です。
===== の違い
localeCompare()Intl.Collator の使い分け
normalize(“NFC”) による表記揺れ対策

「理屈はあとでいいから、まず正しく動く形を知りたい」
そんなときの入口として読める構成にしています。


1. なぜ === を基本にするのか

文字列の一致判定では、まず === を使いましょう。
理由はとてもシンプルです。

== は比較時に、自動で型変換を行うからです。
この挙動が、思わぬ不具合の入口になります。

たとえば、文字列の “1” と数値の 1 は、
== だと true になります。

console.log("1" == 1);  // true
console.log("1" === 1); // false

実務では「見た目が同じ」よりも、
「型まで一致している」ことが重要です。

一覧画面や検索条件の比較でも、
曖昧さを残さないほうが安全です。

厳密等価演算子
値だけでなく、型まで含めて一致しているかを判定する演算子です。

等価演算子
型が違っていても、自動変換したうえで比較する演算子です。

暗黙の型変換
実行時にデータ型が自動で変わることです。意図しない一致の原因になります。


2. なぜ >< では日本語ソートが崩れるのか

「文字列なら a > b で比較できるのでは?」
そう考えたくなりますが、日本語では注意が必要です。

比較演算子は、基本的に
文字の並びをコード順で判定します。

この順番は、私たちが期待する
五十音順や辞書順とは一致しません。

そのため、次のようなズレが起こります。

  • ひらがなとカタカナが直感どおりに並ばない
  • 半角カタカナと全角カタカナが混在すると崩れる
  • 数字を含む文字列が自然な順番にならない

たとえば、ユーザーが求めているのは
「辞書で見る並び」に近い順序です。

一方で、単純比較は
「内部的な文字コードの順序」でしかありません。

この差を理解しておくと、
レビューでも説明しやすくなります。

Unicodeコードポイント
文字ごとに割り当てられた番号です。番号順は、必ずしも日本語の辞書順ではありません。


3. 日本語比較の基本は localeCompare()Intl.Collator

では、どうやって日本語を自然に比較すればよいのでしょうか?
ここで使うのが、言語ルールを考慮できる比較機能です。

代表的なのは localeCompare()Intl.Collator です。

■ 手軽に試せる localeCompare()

まず試しやすいのが localeCompare() です。
文字列同士を、指定したロケールで比較できます。

const list = ["い", "あ", "う"];
list.sort((a, b) => a.localeCompare(b, "ja"));

// ["あ", "い", "う"]

小規模な配列なら、これでも十分です。
「まず正しく並べたい」という場面で役立ちます。

ただし、ソート件数が増えると
比較回数も一気に増えます。

その結果、毎回の比較コストが効いてきて、
画面の体感速度に影響することがあります。

■ 実務で使いやすい Intl.Collator

大量データを扱うなら、私たちは Intl.Collator をおすすめします。
理由は、一度作った比較設定を使い回せるからです。

const collator = new Intl.Collator("ja");

const list = ["い", "あ", "う"];
list.sort(collator.compare);

// ["あ", "い", "う"]

実務で使いやすい理由は、主に3つあります。

  • 比較設定を再利用できる
  • 数値混じりの自然順ソートにも対応できる
  • 一覧画面のような繰り返し処理で安定しやすい

「正しさ」と「扱いやすさ」を両立したいとき、
まず候補にしたい方法です。

String.prototype.localeCompare()
文字列をロケールの規則に従って比較するメソッドです。

Intl.Collator
多言語の文字列比較を効率よく行うためのオブジェクトです。

メモリ効率
同じ処理を無駄なく再利用し、負荷を抑えやすい状態を指します。

関連して、ブラウザ負荷の見方を整理したい場合は、
パフォーマンスタブ徹底解説|Chrome DevToolsでWebパフォーマンス改善の全手順』も参考になります。


4. normalize(“NFC”) が表記揺れ対策で効く理由

「見た目は同じなのに、一致しない……」
この現象も、日本語比較ではよくあります。

代表例が、濁点を含む文字です。
たとえば「ガ」は、内部的には複数の表現がありえます。

  • 1文字として表現された「ガ」
  • 「カ」と濁点を組み合わせた「ガ」

見た目は同じでも、
そのまま比較すると一致しないことがあります。

const str1 = "ガ";
const str2 = "カ\u3099";

console.log(str1 === str2); // false
console.log(str1.normalize("NFC") === str2.normalize("NFC")); // true

ここで役立つのが normalize(“NFC”) です。
比較前に表現形式をそろえることで、表記揺れを吸収できます。

特に、次のような入力元では有効です。

  • ユーザー入力
  • 外部APIのレスポンス
  • CSVやファイル経由の文字列

「表示は同じなのに検索にヒットしない」
そんな不具合を減らすうえで、とても実用的です。

Unicode正規化(NFC)
文字の内部表現を一定の形式にそろえる処理です。

合成済み文字 / 結合文字
1文字として持つ表現と、複数文字の組み合わせで持つ表現のことです。


5. 実務で使いやすい日本語比較テンプレート

ここまでの内容を踏まえて、
すぐ使いやすい形を1つにまとめます。✅

ポイントは、次の2つです。

  • Intl.Collator を使い回す
  • 比較前に normalize(“NFC”) でそろえる
/**
 * 日本語の辞書順ソート用コンパレータ
 * - Intl.Collatorを再利用して高速化
 */
const japaneseCollator = new Intl.Collator("ja", {
  numeric: true,
  sensitivity: "accent",
});

/**
 * 安全な文字列比較関数
 */
const compareJapanese = (a, b) => {
  const cleanA = (a ?? "").normalize("NFC");
  const cleanB = (b ?? "").normalize("NFC");

  return japaneseCollator.compare(cleanA, cleanB);
};

// 使用例
const items = ["第10集", "第2集", "ガンダム", "ガンダム"];
items.sort(compareJapanese);

このテンプレートなら、
数値混じりの並びにも対応しやすくなります。

さらに、濁点の表記差も吸収できるため、
実務の一覧ソートで使い回しやすい形です。

Intl.Collator を関数の外で作るのも重要です。
毎回生成しないぶん、無駄な負荷を減らせます。

undefined の混入で困る場面が多い場合は、
なぜ「undefined」が出る?原因と解決法10選|JavaScript のデバッグに効く実例集』もあわせて確認してみてください。

コンパレータ
2つの値の順序を決めるための比較関数です。

自然順ソート
1, 2, 10 のように、数字を数値として自然に並べる方法です。

オーバーヘッド
本来の処理に加えて発生する追加コストのことです。


6. まず押さえたい実務判断のまとめ

ここまでを、現場目線で整理すると次のようになります。

  • 一致判定は === を使う
  • 日本語ソートは Intl.Collator を使う
  • 比較前に normalize(“NFC”) を通す
  • 数値混じりなら numeric: true を付ける

「どれを選べばよいか迷う」という状態なら、
まずはこの組み合わせで十分戦えます。

実装の正しさだけでなく、
レビューで説明しやすいのも大きな利点です。


FAQ|よくある疑問

Object.is() を使うべき場面はありますか?

通常の文字列比較なら、基本は === で問題ありません。
NaN+0 / -0 のような特殊ケースを厳密に扱いたいときに使います。

■ 漢字も五十音順にきれいに並びますか?

標準機能だけでは、漢字の「読み」までは判断できません。
厳密な五十音順が必要なら、フリガナや読み仮名データを持たせる設計が必要です。

■ パフォーマンス重視なら結論は何ですか?

結論としては、Intl.Collator の再利用が第一候補です。
Reactなら useMemo などで保持し、毎回作り直さない構成が扱いやすいです。

Object.is()
=== に近い比較を行いながら、一部の特殊値をより厳密に判定できるメソッドです。

useMemo
計算結果や生成した値を保持し、再計算を減らすための仕組みです。


7. まとめ|迷ったらこの形で始めましょう

JavaScriptの文字列比較は、
一見シンプルでも実務では落とし穴があります。

特に日本語ソートでは、
単純比較だけでは期待どおりに並びません。

だからこそ、次の流れを基準にすると安心です。

  • 一致判定は ===
  • 並び替えは Intl.Collator
  • 表記揺れ対策は normalize(“NFC”)

まずは手元の一覧画面や検索機能で、
このテンプレートをそのまま試してみてください。

関連して、実務で使えるJavaScriptの考え方を広げたい場合は、
JavaScript中級者へのステップアップ|実務で使えるテクニック10選』も参考になります。

ぜひコードをコピペして、まずは動かしてみてください。

RANKINGranking-icon

LATEST POSTS

もっとルートゼロを知りたいなら

DISCOVER MORE