🏁 はじめに
多くの選択肢から検索・選択できる UI として人気のある Tom Select。
今回はその fuzzy検索(曖昧検索) を使っていて、思いがけず便利な挙動に気づいたのでシェアします。
キーワードはズバリ…
全角と半角の「CD」は区別されない?
日本語環境でありがちな“全角・半角混在問題”。
その悩みを軽減してくれるかもしれない、Tom Select × Fuse.js の組み合わせに注目です。
🔧 使用ライブラリ
-
Tom Select v2.2.2
CDN:<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script> -
Fuse.js(内部で使用)
Tom Select のfuzzy検索はこのライブラリに依存しています。
🧪 検証内容:全角・半角でどうなる?
以下のように「全角CD」「半角CD」が混在したリストを Tom Select に表示し、
fuzzy検索で 「CD」(半角) を入力したときの挙動を確認しました。
🔹 HTMLコード(抜粋)
<select id="fuzzySelect">
<option value="1509">ABザクタンクCD01</option>
<option value="1510">ABザクタンクCD02</option>
<option value="1511">ABザクタンクCD03</option>
<option value="1512">ABザクタンクCD04</option>
</select>
🔹 JavaScript(Tom Select 初期化)
new TomSelect("#fuzzySelect", {
maxItems: 1,
allowEmptyOption: true,
placeholder: "あいまい検索で探す",
onInitialize: function() {
this.clear();
}
});
🔹 ソースコード全体
サンプルコードはここを見てください
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Tom Select - 前方一致 & あいまい検索</title>
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/css/tom-select.css" rel="stylesheet">
<style>
body { font-family: sans-serif; margin: 2em; }
label { font-weight: bold; display: block; margin-top: 1.5em; }
select { width: 100%; max-width: 400px; }
</style>
</head>
<body>
<h2>Tom Select 検索タイプ別サンプル(初期未選択)</h2>
<!-- ▼ 前方一致検索(ドライバー) -->
<label for="prefixSelect">🚚 前方一致検索(パイロット)</label>
<select id="prefixSelect" placeholder="前方一致で検索">
<option value="" disabled selected hidden>-- 選択してください --</option>
<option value="80">123455970 連邦一郎</option>
<option value="81">123452482 ティターンズ太郎</option>
<option value="82">123455157 連邦二郎</option>
<option value="83">123455796 ティターンズ三平</option>
<option value="1117">123453000 テストパイロット</option>
<option value="1133">Zeon0101 ジオン一郎</option>
<option value="1134">Zeon0102 ジオン二郎</option>
<option value="1135">Zeon0103 ジオン三郎</option>
<option value="1136">Zeon0104 ジオン四郎</option>
<option value="1137">Zeon0105 ジオン五郎</option>
</select>
<!-- ▼ あいまい検索(車両) -->
<label for="fuzzySelect">🚗 あいまい検索(モビルスーツ)</label>
<select id="fuzzySelect" placeholder="あいまい検索で探す">
<option value="" disabled selected hidden>-- 選択してください --</option>
<option value="73">グフ99901</option>
<option value="74">グフ99902</option>
<option value="75">グフ99903</option>
<option value="76">グフ99904</option>
<option value="413">ABガンタンクCD</option>
<option value="1509">ABザクタンクCD01</option>
<option value="1510">ABザクタンクCD02</option>
<option value="1511">ABザクタンクCD03</option>
<option value="1512">ABザクタンクCD04</option>
<option value="1513">ABザクタンクCD05</option>
</select>
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script>
<script>
// ▼ 前方一致検索(ドライバー)
new TomSelect("#prefixSelect", {
maxItems: 1,
placeholder: "前方一致で検索",
allowEmptyOption: true,
score: function(search) {
return function(item) {
const label = item.text.toLowerCase();
const keyword = search.toLowerCase();
return label.startsWith(keyword) ? 1 : 0;
};
},
onInitialize: function() {
this.clear();
}
});
// ▼ あいまい検索(車両)
new TomSelect("#fuzzySelect", {
maxItems: 1,
allowEmptyOption: true,
placeholder: "あいまい検索で探す",
onInitialize: function() {
this.clear();
}
});
</script>
</body>
</html>
📷 実際の動作結果
半角「CD」と入力すると、全角「CD」を含む項目もヒットしてくれました!
えっ、Fuse.js って全角と半角を区別するんじゃないの?
と思って調べてみたら…
🤔 全角・半角の区別について調べてみた
✔ Fuse.js は原則として「全角と半角を区別」する
Fuse.js 単体で以下のような比較を行った場合、 "CD" と "CD" は別物扱いになります。
const list = [{ name: "ABCD" }, { name: "ABCD" }];
const fuse = new Fuse(list, { keys: ["name"] });
fuse.search("CD"); // 全角「CD」はヒットしない
🧠 仮説
じゃあなぜ Tom Select でヒットしたのか…?
💡 推測される理由
-
thresholdの設定(ゆるめ)によって、多少の違いは曖昧一致として許容されている - Unicode正規化は明示的にされていないが、視覚的に近い文字列を「近い」と評価している可能性
- Fuse.js の
includeScoreによるスコア判定が「類似」と判断
✅ まとめ
| 比較内容 | 結果 | 補足 |
|---|---|---|
| 半角「CD」 vs 全角「CD」 | ✅ ヒット | Tom Select + Fuse.js の fuzzy検索はスコア的に「近い」と判断 |
| 明示的な normalize() | ❌ 使用していない | それでもヒットしている点が面白い |
| ユーザー体験的には? | 🟢 優しい! | 日本語混在環境でも安心して使える! |
📝 おわりに
今回のように「ちょっと不思議な挙動」に出会ったとき、
それを試して調べて、推測するって…やっぱり楽しいですね!
「Tom Select の fuzzy 検索って全角・半角にもけっこう寛容だな」と感じたので、
日本語UIの改善や、ユーザーの入力ミスを吸収したい場面ではぜひ活用してみてください!