JavaScriptで文字列を比較・処理する前に!String.prototype.normalize()の使い方と注意点


Unicode 正規化 には、いくつかの種類があり、それぞれ異なる処理を行います。String.prototype.normalize() メソッドでは、以下の 4 つの正規化形式を指定することができます。

  • NFKD (Normalization Form Compatibility Decomposition)
    NFD と同様に結合記号を分解し、さらに互換性のある記号に変換します。
  • NFD (Normalization Form Canonical Decomposition)
    すべての結合記号を分解し、基底文字と分離された記号に置き換えます。
  • NFKC (Normalization Form Compatibility Composition)
    NFC と同様に合成文字を分解し、さらに互換性のある記号に変換します。
  • NFC (Normalization Form Canonical Composition)
    すべての合成文字を分解し、基底文字と結合記号に置き換えます。

例:

const text1 = "film"; // ラテン文字小文字 f と i の結合文字
const text2 = "fi\x{332}"; // ラテン文字小文字 f と i の後に結合記号を付けた文字

console.log(text1 === text2); // false

console.log(text1.normalize('NFKC') === text2.normalize('NFKC')); // true

上記の例では、text1text2 は見た目こそ同じですが、実際には異なる文字表現になっています。しかし、normalize() メソッドを使って NFKC 形式に正規化すると、両方の文字列は同じ表現になり、=== 演算子で比較しても true となります。

String.prototype.normalize() メソッドの利点

  • 国際化対応を容易にする
  • データベースや検索エンジンでの文字列の一貫性を保つ
  • 文字列の比較を容易にする

String.prototype.normalize() メソッドの使用例

  • 異なる言語の文字列を比較する
  • 検索クエリの正規化を行い、検索結果の精度を向上させる
  • ユーザー入力された文字列を正規化して、データベースに保存する
  • すべての環境で String.prototype.normalize() メソッドがサポートされているわけではありません。
  • 正規化形式によっては、元の文字列と見た目や意味が異なる場合があります。
  • String.prototype.normalize() メソッドは、処理に時間がかかる場合があります。


const text1 = "film"; // ラテン文字小文字 f と i の結合文字
const text2 = "fi\x{332}"; // ラテン文字小文字 f と i の後に結合記号を付けた文字

console.log(text1 === text2); // false

console.log(text1.normalize('NFKC') === text2.normalize('NFKC')); // true

データベースへの保存

以下のコードは、ユーザー入力された文字列を NFKC 形式に正規化して、データベースに保存する例です。

const userInput = prompt("名前を入力してください: ");
const normalizedName = userInput.normalize('NFKC');

// データベースに normalizedName を保存

検索クエリの正規化

以下のコードは、検索クエリの NFKD 形式に正規化を行い、検索結果の精度を向上させる例です。

const query = prompt("検索クエリを入力してください: ");
const normalizedQuery = query.normalize('NFKD');

// normalizedQuery を使って検索を実行
const germanText = "Hällo"; // ドイツ語の挨拶
const greekText = "Γεια σας"; // ギリシャ語の挨拶

console.log(germanText === greekText); // false

console.log(germanText.normalize('NFD') === greekText.normalize('NFD')); // true


正規表現

正規表現を使用して、文字列から不要な記号や結合文字を削除することができます。ただし、正規表現は複雑になる場合があり、String.prototype.normalize() メソッドよりも処理速度が遅い場合があります。

const text = "film"; // ラテン文字小文字 f と i の結合文字

const normalizedText = text.replace(/[\u{1D179}]/g, "fi");
console.log(normalizedText); // fi

ライブラリ

Unicodeunf などのライブラリを使用して、Unicode 文字列の正規化を行うことができます。これらのライブラリは、String.prototype.normalize() メソッドよりも高速で機能が豊富な場合があります。

const { normalize } = require("unicode-normalization");

const text = "film"; // ラテン文字小文字 f と i の結合文字
const normalizedText = normalize(text, "NFKC");
console.log(normalizedText); // fi

手動変換

簡単な文字列の場合は、手動で変換することもできます。ただし、これは трудоемкий でエラーが発生しやすい方法です。

const text = "film"; // ラテン文字小文字 f と i の結合文字

const normalizedText = "f" + "\x{332}";
console.log(normalizedText); // fi
  • 非常に簡単な文字列の場合
    手動変換
  • より多くの制御が必要な場合
    正規表現
  • 高速な処理が必要な場合
    ライブラリ (例: unicode-normalization, unf)
  • シンプルで使いやすい方法
    String.prototype.normalize() メソッド