JavaScript Tips | 文字列ユーティリティ:検索・置換 - 後方一致

JavaScript JavaScript
スポンサーリンク

「後方一致」とは何をしているのか

前回の「前方一致」は“先頭が合っているか”を見るものでした。
「後方一致」はその逆で、文字列の“末尾”が、指定した文字列と一致しているかどうかを調べます。

「report.csv」が「.csv」で終わっているか?
「photo.jpg」が「.png」では終わっていないか?
「/api/users/123」が「/users」で終わっているか?

こういう判定が全部「後方一致」です。
ファイル拡張子のチェック、URL の末尾パスの判定、メッセージの末尾タグの確認など、
業務コードのあちこちで出てきます。


JavaScript 標準の endsWith の基本

いちばんシンプルな使い方

JavaScript には、後方一致専用のメソッド endsWith が用意されています。

const file = "report.csv";

file.endsWith(".csv"); // true
file.endsWith(".txt"); // false
JavaScript

「この文字列は、指定した文字列で“終わっているか”?」を true / false で返してくれます。

第二引数で「どこまでを対象とするか」も指定できます。

const str = "HelloWorld";

str.endsWith("World");      // true(全体で判定)
str.endsWith("Hello", 5);   // true(先頭から5文字分 "Hello" までを対象に判定)
str.endsWith("World", 5);   // false("Hello" の中には "World" はない)
JavaScript

ここでの重要ポイントは二つです。

文字列の“末尾”だけを見る、ということ。
大文字・小文字は区別される、ということ。

"report.CSV".endsWith(".csv"); // false(大文字小文字が違う)
JavaScript

業務で使いやすくする:大文字・小文字を無視した後方一致

実務では、「拡張子は大文字でも小文字でもいい」といったケースが多いです。
.CSV でも .csv でも同じ扱いにしたい、というやつですね。

そこで、「大文字・小文字を無視した後方一致」ユーティリティを用意します。

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

やっていることを噛み砕きます。

null / undefined が来ても落ちないようにしている。
両方を文字列化してから toLowerCase() で小文字にそろえる。
サフィックス(末尾文字列)が空なら true(検索 UI 的に自然)。
最後は endsWith で後方一致を判定する。

使い方はこうです。

endsWithIgnoreCase("report.CSV", ".csv"); // true
endsWithIgnoreCase("photo.jpg", ".JPG");  // true
endsWithIgnoreCase("document.pdf", ".doc"); // false
JavaScript

これだけで、「大文字・小文字を気にしない後方一致」がどこでも同じ挙動で使えます。


日本語環境らしく:全角・半角も吸収した後方一致

日本語の業務システムだと、「全角・半角の揺れ」もよく問題になります。

例えば、ユーザーが「.csv」(全角ドット+全角英字)と入力してしまうことがあります。
それでも「.csv」と同じものとして扱いたい、という要望は普通にあります。

そこで、「検索用の正規化」を一箇所にまとめてから endsWith する形にします。

function toHalfWidth(str) {
  if (str == null) return "";
  return String(str)
    .replace(/[!-~]/g, (ch) =>
      String.fromCharCode(ch.charCodeAt(0) - 0xFEE0)
    )
    .replace(/ /g, " ");
}

function normalizeForSuffix(str) {
  return toHalfWidth(str).toLowerCase().trimEnd();
}
JavaScript

ここでは、

全角英数字・記号を半角に寄せる。
全角スペースを半角スペースにする。
小文字にそろえる。
末尾の空白だけ削る(後方一致なので末尾が大事)。

という正規化をしています。

これを使って、「ゆるい後方一致」を作ります。

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

  const t = normalizeForSuffix(text);
  const s = normalizeForSuffix(suffix);

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

  return t.endsWith(s);
}
JavaScript

動きを見てみます。

endsWithLoose("report.CSV", ".csv");   // true(全角ドット+全角英字)
endsWithLoose("photo.JPG  ", ".jpg");     // true(末尾スペース無視+大文字小文字無視)
endsWithLoose("log_2026-02-19 ", "2026-02-19"); // true(末尾の全角スペース無視)
endsWithLoose("document.pdf", ".doc");    // false
JavaScript

ここでの一番大事なポイントは、

後方一致の前に“どう正規化するか”をユーティリティに閉じ込めている」ことです。
呼び出し側は endsWithLoose を呼ぶだけで、
大文字・小文字・全角・半角・末尾スペースを意識せずに済みます。


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

ファイル拡張子のチェック

アップロードされたファイルが、許可された拡張子かどうかを判定するのは定番です。

function isCsvFile(name) {
  return endsWithIgnoreCase(name, ".csv");
}

function isImageFile(name) {
  return (
    endsWithIgnoreCase(name, ".png") ||
    endsWithIgnoreCase(name, ".jpg") ||
    endsWithIgnoreCase(name, ".jpeg")
  );
}

isCsvFile("report.csv");    // true
isCsvFile("REPORT.CSV");    // true
isImageFile("photo.JPG");   // true
isImageFile("document.pdf"); // false
JavaScript

ここで endsWithIgnoreCase を使っておくと、
「.CSV だから弾かれた」といった微妙な不具合を防げます。

URL やパスの末尾判定

API のエンドポイントやルーティングで、
「末尾が /users のパスだけを対象にしたい」といったケースもあります。

function isUsersPath(path) {
  return endsWithLoose(path, "/users");
}

isUsersPath("/api/v1/users");      // true
isUsersPath("/api/v1/users/123");  // false
isUsersPath("/USERS");             // true(大文字小文字無視)
JavaScript

「どこに /users が含まれているか」ではなく、
「最後が /users で終わっているか」を見たいときは、
部分一致ではなく後方一致が適切です。

メッセージの末尾タグ・サフィックス判定

ログやメッセージの末尾に、
[OK][NG] のようなタグを付けることがあります。

function isOkMessage(message) {
  return endsWithLoose(message, "[ok]");
}

isOkMessage("処理完了 [OK]");   // true
isOkMessage("処理失敗 [NG]");   // false
JavaScript

「最後に何が付いているか」で判定したいとき、
後方一致はとても素直に書けます。


設計として意識してほしいこと

「後方一致のルール」をユーティリティに閉じ込める

一番大事なのは、
「後方一致のとき、何を無視して、何を区別するか」を決めて、
それをユーティリティに閉じ込めることです。

大文字・小文字を無視するのか。
全角・半角をそろえるのか。
末尾の空白を無視するのか。

これを機能ごとにバラバラに書き始めると、
「この画面では .CSV が通るのに、あっちでは通らない」といった
気持ち悪い差がどんどん増えていきます。

なので、

normalizeForSuffix のような「後方一致用の正規化関数」を一つ決める。
後方一致をしたいときは、必ず endsWithIgnoreCaseendsWithLoose を通す。

というルールにしておくと、
ファイルチェック・URL 判定・メッセージ判定の挙動が一貫して、テストもしやすくなります。


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

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

"report.csv".endsWith(".csv");
"report.CSV".endsWith(".csv");

endsWithIgnoreCase("report.CSV", ".csv");
endsWithLoose("report.CSV  ", ".csv");
endsWithLoose("log_2026-02-19 ", "2026-02-19");
JavaScript

「どこからが true で、どこからが false になるか」を体で覚えると、
「後方一致」と「正規化」のイメージがかなりクリアになります。

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

export function endsWithIgnoreCase(text, suffix) { ... }
export function endsWithLoose(text, suffix) { ... }
JavaScript

のようなユーティリティを一つ置いて、
「拡張子チェックや末尾判定は必ずここを通す」
というルールにしてみてください。

それができた瞬間、あなたの文字列判定は
「その場しのぎの endsWith の寄せ集め」から
「設計された後方一致ユーティリティ」に、一段レベルアップします。

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