JavaScript Tips | 文字列操作:文字列が指定文字列で始まるか判定する

JavaScript JavaScript
スポンサーリンク
スポンサーリンク

業務・実務で使える JavaScript ユーティリティ:文字列が指定文字列で始まるか判定する方法

JavaScriptで「文字列が指定した文字列で始まるか」を判定する処理は、業務・実務で非常によく使います。URLの判定、ファイルパスの確認、プレフィックス付きIDの検証、ログの種類分け、コマンド文字列の簡易判定、CSVやテキストデータの先頭形式チェックなど、用途はかなり幅広いです。

一見すると単純な処理に見えますが、実務では「大文字小文字を区別するのか」「前後の空白をどう扱うのか」「空文字をどう解釈するのか」「null や undefined が来たらどうするのか」「部分一致のように見えて実は厳密さが必要ではないか」といった点を丁寧に考える必要があります。

つまり、文字列が指定文字列で始まるかを判定する処理は、単なる小技ではありません。入力の揺れをどう扱い、どの条件で一致とみなすかを整理する、実務的にとても重要な基礎処理です。

まず理解したい:「始まる」とは何を意味するのか

初心者の方が最初に押さえたいのは、「始まる」という条件は部分一致とは違うということです。たとえば文字列全体の中に含まれていればよいわけではなく、先頭から見て一致している必要があります。

  • "JavaScript" は "Java" で始まる
  • "JavaScript" は "Script" では始まらない
  • "error: invalid token" は "error" で始まる
  • " error: invalid token" は、空白をそのまま含めるなら "error" で始まらない

この最後の例はとても重要です。業務では前後の空白や改行が混ざることがあるため、「生の値のまま判定するのか」「前処理してから判定するのか」を先に決める必要があります。

まずはここを明確にしてください。始まり判定はシンプルですが、どの状態の文字列に対して判定するのかで結果が変わります。

もっとも基本的な方法:startsWith()

JavaScriptで文字列が指定文字列で始まるかを判定する基本は、startsWith() メソッドです。これは初心者の方が最初に覚えるべき方法です。

// 文字列が指定した文字列で始まるかを判定する基本例
const text = "JavaScript";
const result = text.startsWith("Java");

console.log(result); // true
JavaScript

startsWith() は、先頭から見て一致していれば true、そうでなければ false を返します。返り値が真偽値なので、if 文との相性がとてもよいです。

// if文で使う例
const path = "/admin/dashboard";

if (path.startsWith("/admin")) {
  console.log("管理画面向けのパスです");
} else {
  console.log("管理画面向けのパスではありません");
}
JavaScript

単純な先頭一致判定なら、まずはこの startsWith() を使えるようになることが大切です。実務でもかなりの場面でそのまま使えます。

ステップバイステップで考える

ここからは、業務で「文字列が指定文字列で始まるか」を判定するときの考え方を、順番に整理していきます。

ステップ1:対象文字列と先頭に期待する文字列をはっきり分ける

最初にやるべきことは、「何を判定対象にするのか」と「何で始まっていてほしいのか」を明確にすることです。変数名も意識して分けると、コードが読みやすくなります。

// 基本の判定
const text = "order_2025_001";
const prefix = "order_";

console.log(text.startsWith(prefix)); // true
JavaScript

初心者の方は、ここを曖昧にしないことが重要です。特に実務では、似た名前の変数が多くなりやすいため、text と prefix のように役割がわかる名前を使うと保守しやすくなります。

ステップ2:大文字小文字を区別するか決める

startsWith() は、大文字小文字を区別します。ここは実務で非常によく問題になります。

// 大文字小文字は区別される
const text = "JavaScript";

console.log(text.startsWith("Java")); // true
console.log(text.startsWith("java")); // false
JavaScript

たとえば、ユーザー入力、URL、識別子、ログレベルなどでは、大文字小文字の揺れを吸収したいことがあります。その場合は、比較前に同じ形へ正規化します。

// 大文字小文字を無視して判定する例
const text = "JavaScript";
const prefix = "java";

const result = text.toLowerCase().startsWith(prefix.toLowerCase());

console.log(result); // true
JavaScript

この「比較前にそろえる」という考え方は、文字列処理全般でとても重要です。検索、比較、判定の多くで再利用できます。

ステップ3:前後の空白をどう扱うか決める

業務では、フォーム入力やCSVデータ、外部APIの値に前後の空白が混ざることがあります。このとき、生の値で判定するのか、trim() してから判定するのかを決める必要があります。

// 前に空白があると一致しない例
const text = "  error: invalid token";

console.log(text.startsWith("error")); // false
JavaScript

もし「余分な空白は無視したい」という仕様なら、先に trim() します。

// 前後の空白を取り除いてから判定する例
const text = "  error: invalid token";
const result = text.trim().startsWith("error");

console.log(result); // true
JavaScript

ここはかなり大事です。ログ解析や入力チェックでは、余分な空白を無視したいことが多いです。一方で、フォーマット自体に意味があるデータでは、生のまま判定したほうが正しいこともあります。つまり、「正規化してから比較するか」は要件次第です。

ステップ4:空文字をどう扱うか考える

これも見落としやすい重要ポイントです。JavaScriptでは、空文字 "" を渡すと startsWith() は true を返します。

// 空文字は true になる
const text = "hello";

console.log(text.startsWith("")); // true
JavaScript

言語仕様としては正しいですが、業務ロジックでは意図に合わないことがあります。たとえば「接頭辞が指定されているときだけ判定したい」という場合、空文字を有効扱いにするとすべて真になってしまいます。

そのため、実務向けには「prefix が空文字なら false にする」というルールを入れることが多いです。

// 空文字の prefix を無効とする例
function startsWithText(text, prefix) {
  // prefix が空文字なら false を返す
  if (prefix === "") {
    return false;
  }

  return text.startsWith(prefix);
}

console.log(startsWithText("hello", "")); // false
JavaScript

このように、言語仕様そのままでよいかどうかを考える姿勢が重要です。実務では「JavaScriptではこう動く」と「業務要件ではどうあるべきか」を分けて考える必要があります。

ステップ5:null や undefined に備える

実務で特に大切なのがここです。入力は常にきれいな文字列とは限りません。null や undefined に対してそのまま startsWith() を呼ぶとエラーになります。

// これはエラーになる例
const text = null;
console.log(text.startsWith("a")); // TypeError
JavaScript

そのため、防御的に書くなら入力チェックを入れます。

// null / undefined に安全な判定関数
function safeStartsWith(text, prefix) {
  // text または prefix が null / undefined なら false
  if (text == null || prefix == null) {
    return false;
  }

  return String(text).startsWith(String(prefix));
}

console.log(safeStartsWith(null, "a"));        // false
console.log(safeStartsWith("hello", null));    // false
console.log(safeStartsWith("hello", "he"));    // true
JavaScript

ここで String() を使っているのは、数値などが来ても文字列として扱えるようにするためです。実務では、関数がどこまで入力の揺れを吸収するかをあらかじめ決めておくことが重要です。

indexOf() でも似たことはできるが、今は startsWith() が基本

古いコードでは、startsWith() の代わりに indexOf() を使って先頭一致を判定していることがあります。

// indexOf() で先頭一致を判定する例
const text = "JavaScript";
const result = text.indexOf("Java") === 0;

console.log(result); // true
JavaScript

これは「見つかった位置が 0 なら先頭一致」という考え方です。ただし、読みやすさの面では startsWith() のほうが明確です。

初心者の方は、まず startsWith() を基本として覚えれば十分です。indexOf() は既存コードを読むための知識として持っておくとよいです。

実務で重要な注意点

先頭一致で十分か、本当は完全一致が必要かを考える

ここはとても重要です。先頭一致は便利ですが、要件によっては不十分です。たとえば、識別子や権限コードの厳密な一致が必要なのに、先頭一致で済ませてしまうと誤判定につながります。

// 先頭一致では誤判定になる可能性がある例
const role = "admin_readonly";

console.log(role.startsWith("admin")); // true
JavaScript

この判定は「admin で始まる」ことは確認できますが、「権限が admin そのものか」は確認できません。完全一致が必要なら === を使うべきです。

// 完全一致にするべき例
const role = "admin_readonly";

console.log(role === "admin"); // false
JavaScript

つまり、先頭一致は便利ですが、使いどころを間違えないことが大切です。

セキュリティ判定を単純な先頭一致だけに頼らない

情報セキュリティの観点では、ここも非常に重要です。単純な startsWith() だけで安全性や認可を判断するのは危険なことがあります。

たとえばURLの許可判定、ファイルパスの検査、権限文字列の確認などで、単純な先頭一致だけに頼ると、想定外の表記ゆれや別形式の入力を見落とすことがあります。

特に注意したい例を挙げます。

  • 許可URLかどうかを文字列の先頭だけで判定する
  • 管理者用パスかどうかを単純な接頭辞だけで判定する
  • 危険コマンドかどうかを先頭文字列だけで判定する

こうした場面では、単純な文字列比較だけではなく、URLとして正しく解析する、ルートを厳密に比較する、権限モデルを別途設計するなど、構造的な検証が必要です。小さなユーティリティだからこそ、用途を超えて過信しないことが大切です。

前処理しすぎると意味が変わることがある

trim() や toLowerCase() は便利ですが、常に使えばよいわけではありません。たとえば、空白や大文字小文字に意味があるデータでは、前処理によって本来の意味を変えてしまうことがあります。

そのため、初心者の方は「とりあえず前処理する」のではなく、「このデータでは何を無視してよいのか」を考える習慣をつけるとよいです。

実務向けの完成版テンプレート

ここまでの注意点を踏まえて、業務・実務で使いやすい安全寄りのテンプレートを紹介します。これは、null 安全、空文字対策、大文字小文字の切り替え、前後空白の除去オプションを備えた例です。

/**
 * 文字列が指定した文字列で始まるか判定する
 *
 * 仕様:
 * - text または prefix が null / undefined の場合は false
 * - prefix が空文字の場合は false
 * - ignoreCase が true の場合は大文字小文字を無視する
 * - trimInput が true の場合は text の前後空白を除去してから判定する
 */
function startsWithText(text, prefix, options = {}) {
  // オプションの初期値を設定する
  const {
    ignoreCase = false,
    trimInput = false
  } = options;

  // text または prefix が null / undefined なら false
  if (text == null || prefix == null) {
    return false;
  }

  // 文字列へ変換する
  let source = String(text);
  let target = String(prefix);

  // prefix が空文字なら false
  if (target === "") {
    return false;
  }

  // 必要なら前後の空白を除去する
  if (trimInput) {
    source = source.trim();
  }

  // 必要なら大文字小文字を無視する
  if (ignoreCase) {
    source = source.toLowerCase();
    target = target.toLowerCase();
  }

  // 先頭一致判定
  return source.startsWith(target);
}

// 使用例
console.log(startsWithText("JavaScript", "Java")); // true
console.log(startsWithText("JavaScript", "java")); // false
console.log(startsWithText("JavaScript", "java", { ignoreCase: true })); // true
console.log(startsWithText("  error: invalid", "error", { trimInput: true })); // true
console.log(startsWithText(null, "error")); // false
console.log(startsWithText("hello", "")); // false
JavaScript

このテンプレートのよい点は、何をどう扱うかがコードから読み取れることです。実務では、短さよりも仕様の見通しのよさが価値になります。

例題で理解を深める

例題1:プレフィックス付きIDの確認

// IDが USER_ で始まるかを確認する例
const userId = "USER_12345";

if (startsWithText(userId, "USER_")) {
  console.log("ユーザーID形式です");
}
JavaScript

このような接頭辞付きIDは実務でよくあります。シンプルですが有効な使い方です。

例題2:ログレベルの判定

// ログの先頭が error かを確認する例
const log = "ERROR: Invalid token";

if (startsWithText(log, "error", { ignoreCase: true })) {
  console.log("エラーログです");
}
JavaScript

ログは大文字小文字が揺れやすいため、無視して比較するのが便利です。

例題3:URLスキームの簡易チェック

// URLが https:// で始まるかを確認する例
const url = "https://example.com";

if (startsWithText(url, "https://")) {
  console.log("HTTPSのURLです");
}
JavaScript

ただし、本格的なURL検証ではこれだけでは不十分です。文字列がそのように始まっていても、正しいURLとは限らないからです。簡易チェックには使えますが、厳密な検証とは分けて考える必要があります。

例題4:前後空白を含む入力の判定

// 前後空白を無視して判定する例
const input = "   CMD:EXPORT";

if (startsWithText(input, "CMD:", { trimInput: true })) {
  console.log("コマンド形式の入力です");
}
JavaScript

外部入力ではこのようなケースが珍しくありません。前処理してから判定する設計が役立ちます。

テストで挙動を確認する

ユーティリティ関数は、小さく見えても仕様差でバグが出やすいです。そのため、代表的なケースをまとめて確認することが大切です。

// 代表的なテストケース
const testCases = [
  ["JavaScript", "Java", {}, true],
  ["JavaScript", "java", {}, false],
  ["JavaScript", "java", { ignoreCase: true }, true],
  ["  error: invalid", "error", {}, false],
  ["  error: invalid", "error", { trimInput: true }, true],
  ["hello", "", {}, false],
  [null, "a", {}, false],
  ["USER_001", "USER_", {}, true]
];

for (const [text, prefix, options, expected] of testCases) {
  const actual = startsWithText(text, prefix, options);

  console.log({
    text,
    prefix,
    options,
    expected,
    actual,
    pass: actual === expected
  });
}
JavaScript

このようにテストケースを並べると、「空文字はどうするか」「大文字小文字はどうするか」「trim するかどうか」といった仕様が明確になります。実務では、こうした明文化がとても重要です。

初心者がつまずきやすいポイント

includes() と startsWith() を混同する

これは非常によくあります。includes() は途中に含まれていても true ですが、startsWith() は先頭一致だけを見ます。どちらを使うべきかを意識することが大切です。

大文字小文字の違いを見落とす

見た目では同じに見えても、JavaScriptは大文字小文字を区別します。ログ、入力値、識別子の比較では、比較前にそろえるべきかを考える必要があります。

空文字の挙動を知らない

startsWith("") が true になることは意外な落とし穴です。業務ではそのままだと困ることが多いため、明示的に無効化する設計がよく使われます。

入力値を信用してしまう

これは実務で特に大切です。null、undefined、数値、余分な空白付き文字列など、さまざまな入力が来る前提で考えるべきです。ユーティリティ関数こそ、防御的プログラミングを練習する絶好の題材です。

より実務的に考えるための確認ポイント

実装前に、次の点を確認しておくと失敗しにくくなります。

  • 本当に先頭一致でよいのか、それとも完全一致が必要か
  • 大文字小文字を区別するか
  • 前後の空白を無視するか
  • 空文字を有効な接頭辞として扱うか
  • null や undefined はどう扱うか
  • セキュリティ判断に使ってよい処理か、それとも構造的な厳密検証が必要か

この確認を先にしておくと、「動くけれど危ないコード」ではなく、「要件に合っていて壊れにくいコード」に近づけます。

すぐ使える最終テンプレート

最後に、そのまま業務で流用しやすい形のテンプレートをまとめます。

/**
 * 文字列が指定した文字列で始まるかを判定する
 *
 * @param {any} text - 判定対象の値
 * @param {any} prefix - 先頭に期待する文字列
 * @param {Object} options - オプション
 * @param {boolean} options.ignoreCase - true の場合は大文字小文字を無視する
 * @param {boolean} options.trimInput - true の場合は前後空白を除去してから判定する
 * @returns {boolean} 先頭一致なら true、そうでなければ false
 */
function startsWithText(text, prefix, options = {}) {
  // オプションの初期値
  const {
    ignoreCase = false,
    trimInput = false
  } = options;

  // null / undefined は false にする
  if (text == null || prefix == null) {
    return false;
  }

  // 文字列に変換する
  let source = String(text);
  let target = String(prefix);

  // 空文字の prefix は無効とする
  if (target === "") {
    return false;
  }

  // 必要なら前後の空白を削除する
  if (trimInput) {
    source = source.trim();
  }

  // 必要なら大文字小文字を無視する
  if (ignoreCase) {
    source = source.toLowerCase();
    target = target.toLowerCase();
  }

  // 先頭一致を判定する
  return source.startsWith(target);
}

// 使用例
console.log(startsWithText("JavaScript utility", "Java")); // true
console.log(startsWithText("JavaScript utility", "java")); // false
console.log(startsWithText("JavaScript utility", "java", { ignoreCase: true })); // true
console.log(startsWithText("  error: invalid", "error", { trimInput: true })); // true
console.log(startsWithText("USER_001", "USER_")); // true
console.log(startsWithText(null, "USER_")); // false
console.log(startsWithText("hello", "")); // false
JavaScript

まとめ

JavaScriptで文字列が指定文字列で始まるかを判定する処理は、startsWith() を中心に書けます。しかし実務では、単に使えるだけでは不十分です。大文字小文字、空文字、前後空白、null、先頭一致で本当に十分かといった点を丁寧に考える必要があります。

特に大切なのは次の点です。

  • startsWith() は先頭一致であり、部分一致や完全一致とは違うことを理解すること
  • 大文字小文字を区別するかどうかを先に決めること
  • 前後空白や空文字をどう扱うかを明確にすること
  • 認可や安全性判断を単純な先頭一致だけに頼らないこと
  • テストケースを用意して仕様を確認すること

初心者の方は、まず startsWith() の基本をしっかり身につけ、そのうえで「入力をそのまま信用しない」「用途に応じて前処理と比較方法を選ぶ」という実務的な視点を持つことが重要です。こうした小さなユーティリティの品質が、アプリ全体の読みやすさ、壊れにくさ、安全性につながっていきます。

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