JavaScript Tips | 文字列ユーティリティ:検索・置換 - 大文字小文字無視検索

JavaScript JavaScript
スポンサーリンク

「大文字小文字無視検索」とは何をしてくれるのか

まずゴールのイメージからいきます。
次の3つの文字列を見てください。

"Apple"
"apple"
"APPLE"

人間からすると「全部 Apple でしょ」ですが、コンピュータ的には全部別物です。
そのまま includes("apple") すると、 "Apple""APPLE" はヒットしません。

でも業務では、「大文字か小文字かなんてどうでもいいから、とにかく“apple”を含むものを探したい」という場面が圧倒的に多いです。
この「大文字・小文字の違いを無視して検索する」ための小さな道具が、大文字小文字無視検索ユーティリティです。


なぜ毎回その場で書かず、ユーティリティにするのか

大文字小文字を無視したいとき、よくやるのはこういう書き方です。

text.toLowerCase().includes(keyword.toLowerCase());
JavaScript

一見これで十分に見えますが、実務では次のような問題が出てきます。

同じようなコードが画面ごとにコピペされる。
どこか一箇所だけ toUpperCase を使っていたりして挙動が微妙に違う。
null や undefined が来たときに片方だけ落ちる。

こういう「じわじわ効いてくる不具合」を避けるために、
“検索用の正規化”を一箇所にまとめたユーティリティを用意しておく価値があります。


基本の考え方:両方を同じルールで正規化してから検索する

大文字小文字無視検索の本質は、とてもシンプルです。

検索対象の文字列を、あるルールで正規化する。
検索キーワードも、同じルールで正規化する。
正規化後の文字列同士で、includesindexOf などを使って検索する。

ここでいう「正規化」の最低限は、小文字にそろえることです。
つまり、「全部小文字にしてから検索する」ということです。


実装例:大文字小文字無視の部分一致検索

まずは一番基本のユーティリティ

部分一致(どこかに含まれていればOK)のケースからいきます。

function includesIgnoreCase(text, keyword) {
  if (text == null || keyword == null) return false;

  const t = String(text).toLowerCase();
  const k = String(keyword).toLowerCase();

  if (k === "") return true;

  return t.includes(k);
}
JavaScript

重要なポイントを噛み砕きます。

textkeyword が null / undefined でも落ちないように、最初にチェックしていること。
String(...) で一度文字列に変換してから toLowerCase() していること。
キーワードが空文字のときは true を返していること(検索 UI 的に自然な挙動)。
最後は普通の includes で判定しているだけなこと。

使い方はこんな感じです。

includesIgnoreCase("Apple Pie", "apple");   // true
includesIgnoreCase("APPLE PIE", "apple");   // true
includesIgnoreCase("apple pie", "APPLE");   // true
includesIgnoreCase("Banana Cake", "apple"); // false
JavaScript

「大文字小文字を無視して検索したい」という要件は、ほぼこれで満たせます。


前方一致・後方一致にもそのまま応用できる

大文字小文字無視検索の考え方は、部分一致だけの話ではありません。
前方一致(先頭が一致しているか)、後方一致(末尾が一致しているか)にも、そのまま使えます。

例えば前方一致ならこうです。

function startsWithIgnoreCase(text, prefix) {
  if (text == null || prefix == null) return false;

  const t = String(text).toLowerCase();
  const p = String(prefix).toLowerCase();

  if (p === "") return true;

  return t.startsWith(p);
}
JavaScript

後方一致ならこうです。

function endsWithIgnoreCase(text, suffix) {
  if (text == null || suffix == null) return false;

  const t = String(text).toLowerCase();
  const s = String(suffix).toLowerCase();

  if (s === "") return true;

  return t.endsWith(s);
}
JavaScript

どちらも「両方を小文字にそろえてから、標準メソッドで判定する」という同じパターンです。
つまり、「大文字小文字無視」は“前処理のルール”であって、“検索の種類”とは独立しているということです。


業務での具体的な使いどころ

一覧画面の検索・絞り込み

ユーザー一覧や商品一覧の検索ボックスでは、
ユーザーが大文字で打つか小文字で打つかなんて、いちいち気にしてほしくありません。

const users = [
  { name: "Taro Yamada" },
  { name: "Hanako Sato" },
  { name: "taro Suzuki" },
];

function filterUsersByName(users, keyword) {
  return users.filter((user) =>
    includesIgnoreCase(user.name, keyword)
  );
}

filterUsersByName(users, "taro");
// Taro Yamada / taro Suzuki の2件がヒット
JavaScript

ここで includesIgnoreCase を使っておけば、
「Taro」「taro」「TARO」どれで検索しても同じ結果になります。

メールアドレスやユーザーIDの検索

メールアドレスやユーザーIDは、
「大文字小文字を区別しない」と決めることが多いです。

const users = [
  { email: "taro@example.com" },
  { email: "HANAKO@example.com" },
];

function findByEmail(users, email) {
  return users.find((user) =>
    includesIgnoreCase(user.email, email)
  );
}

findByEmail(users, "TARO@example.com");   // taro@example.com が見つかる
findByEmail(users, "hanako@EXAMPLE.COM"); // HANAKO@example.com が見つかる
JavaScript

本当は「保存時に小文字に正規化しておく」のがベストですが、
既存データが混在している場合でも、
大文字小文字無視検索ユーティリティがあると、かなり救われます。


設計として一番大事なポイント

「検索用の正規化」を一箇所にまとめる

ここが本当に重要です。

大文字小文字無視検索を、毎回こう書いてしまうとします。

text.toLowerCase().includes(keyword.toLowerCase());
JavaScript

一見同じことをしているようで、現場ではこうなりがちです。

どこか一箇所だけ toUpperCase を使っている。
どこか一箇所だけ trim() を足している。
どこか一箇所だけ null チェックを忘れている。

結果として、「画面Aではヒットするのに、画面Bではヒットしない」という
ユーザーから見て意味不明な差が生まれます。

それを防ぐために、

「大文字小文字無視検索は includesIgnoreCase を必ず使う」
「前方一致なら startsWithIgnoreCase、後方一致なら endsWithIgnoreCase を使う」

というルールにしてしまうのが、設計としてとても強いです。

「何を無視して、何を区別するか」を明文化する

大文字小文字だけでなく、
全角・半角、前後のスペース、記号の扱いなど、
「どこまでを同じとみなすか」はプロダクトごとに違います。

例えば、もう一歩踏み込んで「全角英数字も半角に寄せる」なら、
toLowerCase() の前に全角→半角の処理を入れて、
それを normalizeForSearch のような関数にまとめておくとよいです。

大事なのは、

「この検索は、大文字小文字だけ無視する」
「この検索は、大文字小文字+全角半角も無視する」

といった“ルール”を、関数名やコメントでちゃんと表現しておくことです。


ちょっとだけ手を動かしてみる

ブラウザのコンソールで、次のあたりを試してみてください。

"Apple Pie".includes("apple");
"Apple Pie".toLowerCase().includes("apple");
includesIgnoreCase("Apple Pie", "apple");
includesIgnoreCase("APPLE PIE", "Apple");
includesIgnoreCase(null, "apple");
includesIgnoreCase("Banana Cake", "");
JavaScript

どこからが true で、どこからが false になるかを体で感じてみてください。
特に「null でも落ちない」「空文字キーワードは true」という挙動が、
実務でどれだけ効いてくるかをイメージできると、一気に設計の目線が上がります。

そのうえで、自分のプロジェクトに

export function includesIgnoreCase(text, keyword) { ... }
JavaScript

を一つ置いて、
「大文字小文字を無視したい検索は、必ずここを通す」
というルールにしてみてください。

その瞬間、あなたの検索処理は
「その場しのぎの toLowerCase の寄せ集め」から
「意図を持って設計された検索ユーティリティ」に、一段レベルアップします。

タイトルとURLをコピーしました