1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

濁点・半濁点が検索にヒットしない原因と対策(Unicode正規化)

1
Posted at

はじめに

ある開発で、検索欄にキーワードを入力すると
本来ヒットするはずのデータが一部表示されない という問題に遭遇しました。

調査を進めてみると、
濁点・半濁点を含む文字列だけが検索結果に表示されていない
ことが分かりました。

何が起こっていたのか

原因は、Unicode正規化形式の不一致でした。

  • 保存されているデータ:NFD
  • 検索キーワード:NFC

この状態で文字列検索(includesLIKE など)を行っていたため、
見た目は同じでもバイト列が異なり、マッチしなかった というわけです。

NFC・NFDとは何か

NFC・NFDは Unicode正規化形式 と呼ばれるもので、
「見た目が同じ文字を、どのようなバイト列で表現するか」のルールです。

例:「ぱ」のUnicode表現

NFC

  • 「ぱ」を 1文字(合成文字) として扱う

NFD

  • 「は」 + 「゜」に 分解 して表現する

なぜ検索にヒットしなかったのか

見た目は同じ「ぱ」でも、

  • NFC: (1文字)
  • NFD: は + ゜(2文字)

という 異なるUnicode表現 になっていました。

そのため、文字列としては一致せず、
検索条件にヒットしていなかった、という結果になります。

今回この問題が起きた理由

原因をさらに追っていくと、
macOSで作成したファイル名がNFDで保存されていた ことが分かりました。

macOSでは仕様として、
ファイル名が自動的にNFDへ正規化される ようになっています。
(なぜそんなことを....)

このNFDの文字列をそのままDBなどに保存し、
検索時にはNFCの文字列を使っていたため、
正規化形式の不一致が発生していました。

対策

保存時・検索時の両方で正規化形式を統一する ことで解決しました。

const s = "";

// NFCに正規化
const normalized = s.normalize("NFC");
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?