「前方一致」とは何をしているのか
まず言葉の整理からいきます。
「前方一致」は、文字列の“先頭”が、指定した文字列と一致しているかどうかを調べることです。
「山田太郎」が「山田」で始まっているか?
「https://example.com」が「https://」で始まっているか?
「ERROR: DB connection failed」が「ERROR」で始まっているか?
こういう判定が全部「前方一致」です。
部分一致が「どこかに含まれていればOK」なのに対して、
前方一致は「先頭からきっちり合っているか」を見る、もう少し厳しめのチェックです。
JavaScript 標準の startsWith の基本
JavaScript には、前方一致専用のメソッド startsWith が用意されています。
const str = "Hello World";
str.startsWith("He"); // true
str.startsWith("Hello"); // true
str.startsWith("World"); // false(先頭ではない)
JavaScriptstartsWith は、
「この文字列は、指定した文字列で“始まっているか”?」を true / false で返します。
第二引数で「どこから判定を始めるか」も指定できます。
const str = "Saturday night plans";
str.startsWith("Sat"); // true(先頭から)
str.startsWith("Sat", 3); // false(インデックス3から見ると "urday...")
JavaScriptここでの重要ポイントは二つです。
1つ目は、「前方一致=startsWith が素直に使える」ということ。
2つ目は、「大文字・小文字は区別される」ということです。
"Hello".startsWith("He"); // true
"Hello".startsWith("he"); // false(小文字なので一致しない)
JavaScript業務で使いやすくする:大文字・小文字を無視した前方一致
実務では、「大文字・小文字の違いは気にしたくない」ことが多いです。
例えば、URL のプロトコル判定や、コマンド名の判定などです。
そこで、「大文字・小文字を無視した前方一致」ユーティリティを一つ用意しておきます。
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やっていることを噛み砕きます。
text / prefix が null や undefined でも落ちないようにしている。
両方を文字列化してから toLowerCase() で小文字にそろえる。
プレフィックスが空文字なら true(検索 UI 的に自然な挙動)。
最終的には startsWith で前方一致を判定する。
使い方はこんな感じです。
startsWithIgnoreCase("HelloWorld", "he"); // true
startsWithIgnoreCase("helloWorld", "HE"); // true
startsWithIgnoreCase("WorldHello", "he"); // false
JavaScriptこれだけで、「大文字・小文字を気にしない前方一致」がどこでも同じ挙動で使えるようになります。
さらに日本語環境らしく:全角・半角も吸収した前方一致
日本語の業務システムだと、「全角・半角の揺れ」もよく問題になります。
「HTTP://example.com」でも「http://」として扱いたい。
「 ERROR: …」(全角スペース)でも「error」で始まるとみなしたい。
そこで、「検索用の正規化」を一箇所にまとめてから startsWith する、という形にします。
まずは簡易的な全角→半角+小文字化の正規化関数です。
function toHalfWidth(str) {
if (str == null) return "";
return String(str)
.replace(/[!-~]/g, (ch) =>
String.fromCharCode(ch.charCodeAt(0) - 0xFEE0)
)
.replace(/ /g, " ");
}
function normalizeForPrefix(str) {
return toHalfWidth(str).toLowerCase().trimStart();
}
JavaScriptここでは、
全角英数字・記号を半角に寄せる。
全角スペースを半角スペースにする。
小文字にそろえる。
先頭の空白だけ削る(前方一致なので先頭が大事)。
という正規化をしています。
これを使って、「ゆるい前方一致」を作ります。
function startsWithLoose(text, prefix) {
if (text == null || prefix == null) return false;
const t = normalizeForPrefix(text);
const p = normalizeForPrefix(prefix);
if (p === "") return true;
return t.startsWith(p);
}
JavaScript動きを見てみます。
startsWithLoose("HTTP://example.com", "http://"); // true
startsWithLoose(" http://example.com", "HTTP://"); // true(先頭スペース無視+大文字小文字無視)
startsWithLoose(" ERROR: something", "error"); // true(全角スペース+全角英字)
startsWithLoose("INFO: ok", "error"); // false
JavaScriptここでの一番大事なポイントは、
「前方一致の前に“どう正規化するか”をユーティリティに閉じ込めている」ことです。
呼び出し側は startsWithLoose を呼ぶだけで、
大文字・小文字・全角・半角・先頭スペースを意識せずに済みます。
実務での具体的な使いどころ
URL のプロトコル判定
「http か https かで処理を分けたい」というのは、よくあるパターンです。
function isHttpUrl(url) {
return startsWithIgnoreCase(url, "http://");
}
function isHttpsUrl(url) {
return startsWithIgnoreCase(url, "https://");
}
isHttpUrl("HTTP://example.com"); // true
isHttpsUrl("https://example.com"); // true
JavaScriptstartsWithIgnoreCase を使うことで、
大文字・小文字を気にせずに素直に書けます。
ログレベルやメッセージ種別の判定
ログの先頭に「ERROR」「WARN」「INFO」などを付けている場合、
前方一致でレベルを判定できます。
function isErrorLog(message) {
return startsWithLoose(message, "error");
}
isErrorLog("ERROR: DB connection failed"); // true
isErrorLog("error: timeout"); // true
isErrorLog(" INFO: ok"); // false(先頭が info)
JavaScript「先頭に何が書いてあるか」で分岐する処理は、
前方一致と相性がとても良いです。
入力補完・サジェストのフィルタ
検索ボックスやプルダウンの候補を、
「先頭がキーワードと一致するものだけ」に絞りたいこともあります。
const items = ["Apple", "Apricot", "Banana", "Grape"];
function filterByPrefix(list, keyword) {
return list.filter((item) => startsWithIgnoreCase(item, keyword));
}
filterByPrefix(items, "ap"); // ["Apple", "Apricot"]
JavaScript部分一致だとヒットしすぎるときに、
前方一致で「頭から合っているものだけ」に絞ると、
ユーザーにとっても分かりやすい挙動になります。
設計として意識してほしいこと
「前方一致のルール」をユーティリティに閉じ込める
一番大事なのは、
「前方一致のとき、何を無視して、何を区別するか」を決めて、
それをユーティリティに閉じ込めることです。
大文字・小文字を無視するのか。
全角・半角をそろえるのか。
先頭の空白を無視するのか。
これを画面ごと・機能ごとにバラバラに書き始めると、
「この画面ではヒットするのに、あっちではヒットしない」といった
気持ち悪い差がどんどん増えていきます。
なので、
normalizeForPrefix のような「前方一致用の正規化関数」を一つ決める。
前方一致をしたいときは、必ず startsWithIgnoreCase や startsWithLoose を通す。
というルールにしておくと、
検索・判定まわりの挙動が一貫して、テストもしやすくなります。
ちょっとだけ手を動かしてみる
コンソールで、次のあたりを試してみてください。
"HelloWorld".startsWith("He");
"HelloWorld".startsWith("he");
startsWithIgnoreCase("HelloWorld", "he");
startsWithLoose("HTTP://example.com", "http://");
startsWithLoose(" ERROR: something", "error");
JavaScript「どこからが true で、どこからが false になるか」を体で覚えると、
「前方一致」と「正規化」のイメージがかなりクリアになります。
そのうえで、自分のプロジェクトに
export function startsWithIgnoreCase(text, prefix) { ... }
export function startsWithLoose(text, prefix) { ... }
JavaScriptのようなユーティリティを一つ置いて、
「前方一致判定は必ずここを通す」というルールにしてみてください。
それができた瞬間、あなたの検索・判定ロジックは
「その場しのぎの startsWith の寄せ集め」から
「設計された前方一致ユーティリティ」に、一段レベルアップします。
