JavaScript Tips | 文字列操作:文字列を単語配列に変換する

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

業務・実務で使える JavaScript ユーティリティ:文字列を単語配列に変換する方法

JavaScriptで文字列を単語配列に変換する処理は、業務開発で非常によく使います。検索キーワードの分割、タグ解析、CSVやフォーム入力の前処理、ファイル名や識別子の正規化、ログ解析、簡単な自然言語処理の前段など、出番はかなり多いです。

一見すると、文字列を split(" ") で区切れば終わりに見えるかもしれません。しかし実務では、空白が連続していたり、ハイフンやアンダースコアが混ざっていたり、camelCase や PascalCase のように見た目では単語がつながっていたりします。さらに、null や undefined、数値、記号、日本語が混ざるケースも珍しくありません。

そのため、単語配列への変換は「ただ区切る処理」ではなく、「入力文字列を業務で扱いやすい単位へ正規化する処理」と考えることが大切です。初心者の段階では特に、最初から難しい正規表現に飛びつくのではなく、何をどう分割したいのかを段階的に整理していくことが重要です。

まず理解したい:単語配列に変換するとはどういうことか

文字列を単語配列に変換するとは、ひとつの文字列を意味のある単位ごとに分割して、JavaScriptの配列として扱えるようにすることです。

たとえば次のような変換です。

  • "red green blue" → ["red", "green", "blue"]
  • "user-name-info" → ["user", "name", "info"]
  • "userNameInfo" → ["user", "Name", "Info"] または最終的に ["user", "name", "info"]
  • " API endpoint url " → ["API", "endpoint", "url"]

この処理が重要なのは、後続のロジックが書きやすくなるからです。たとえば単語ごとに先頭大文字化して Title Case を作ったり、アンダースコアでつないで snake_case にしたり、大文字にして CONSTANT_CASE を作ったりできます。

つまり、単語配列への変換は、さまざまな文字列操作の土台になるユーティリティです。

最初に決めるべき仕様

実務で最初にやるべきことは、コードを書くことではありません。どんな入力を受け取り、どんな単語配列を返したいかを決めることです。ここを曖昧にすると、途中で「この記号は残すのか」「数字は単語として扱うのか」「日本語はどうするのか」といった問題が次々に発生します。

たとえば、次のような入力をどう扱うかを最初に考えます。

  • "first name" は空白で分けて ["first", "name"] にするのか
  • "first-name" はハイフンも区切りとして扱うのか
  • "first_name" はアンダースコアも区切りにするのか
  • "firstName" は camelCase を分割対象にするのか
  • "XMLHttpRequest" のような連続大文字をどう分けるのか
  • "version2File" の数字を単語の一部として残すのか
  • null や undefined は空配列にするのか
  • 日本語のように空白がない文字列をどう扱うのか

ここで大切なのは、「万能な正解」を探さないことです。業務では、データの性質に合わせた仕様が正解になります。たとえば英数字の識別子だけを扱うなら、比較的シンプルなルールで十分です。一方で自然文に近い文字列を扱うなら、より慎重な設計が必要です。

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

ここからは、文字列を単語配列へ変換する流れを、初心者向けに順を追って見ていきます。

ステップ1:まずは前後の空白を取り除く

フォーム入力やCSV、外部データには、前後に余計な空白が入っていることがよくあります。そのまま分割すると、空の要素が混ざる原因になります。まずは trim() で前後の空白を削除します。

// 前後の空白を取り除く例
const input = "  red green blue  ";
const trimmed = input.trim();

console.log(trimmed); // "red green blue"
JavaScript

この処理は地味ですが重要です。実務では、後ろの処理をきれいにするために、最初にノイズを落とす考え方が非常に役立ちます。

ステップ2:どの区切り文字を単語の境界として扱うか決める

初心者が最初に思いつきやすいのは split(" ") です。これは空白1文字で分割する方法です。

// 空白1文字で分割する基本例
const input = "red green blue";
const words = input.split(" ");


console.log(words); // ["red", "green", "blue"]
JavaScript

ただし、この方法にはすぐ限界があります。たとえば空白が複数あると、空文字が混ざります。

// 空白が連続すると空文字が混ざる例
const input = "red   green   blue";
const words = input.split(" ");

console.log(words); // ["red", "", "", "green", "", "", "blue"]
JavaScript

この問題を避けるには、正規表現を使って「1個以上の空白」で分割します。

// 1個以上の空白で分割する例
const input = "red   green   blue";
const words = input.trim().split(/\s+/);

console.log(words); // ["red", "green", "blue"]
JavaScript

\s+ は「空白文字が1個以上続く部分」を意味します。これにより、スペースが何個続いていても、ひとつの区切りとして扱えます。

ステップ3:空白以外の区切りもそろえる

実務では、単語の区切りは空白だけではありません。ハイフン、アンダースコア、スラッシュ、ドットなどが混ざることもあります。

たとえば次のような入力です。

  • "user-name-info"
  • "user_name_info"
  • "user.name/info"

こうしたケースでは、いきなり split() するより、まず区切り文字を共通の記号へ寄せるほうが理解しやすいです。たとえば、区切りっぽい文字を全部スペースにそろえてから分割します。

// ハイフンやアンダースコアなどを空白にそろえてから分割する例
const input = "user-name_info.test";
const normalized = input.replace(/[-_.]+/g, " ");
const words = normalized.trim().split(/\s+/);

console.log(words); // ["user", "name", "info", "test"]
JavaScript

この書き方のよい点は、処理の意味が読みやすいことです。初心者の方は、複雑な正規表現を一発で書こうとするより、「いったんそろえる」「そのあと分ける」と段階を分けて考えるほうが理解しやすくなります。

ステップ4:camelCase と PascalCase をどう扱うか

実務では userName や UserName のような文字列もよく現れます。これらは空白も記号もないため、そのままでは分割できません。

そこで、「小文字や数字の直後に大文字が来たら、そこを単語の境目とみなす」というルールで区切ります。

// camelCase の境目に空白を入れる例
const input = "userNameInfo";
const separated = input.replace(/([a-z0-9])([A-Z])/g, "\$1 $2");
const words = separated.split(" ");

console.log(words); // ["user", "Name", "Info"]
JavaScript

この処理では、まず userNameInfo を user Name Info に変換し、その後で空白区切りしています。

さらに、後続処理で全部小文字にしたければ、map() を使ってそろえられます。

// camelCase を分割したあとで小文字にそろえる例
const input = "userNameInfo";
const words = input
  .replace(/([a-z0-9])([A-Z])/g, "\$1 $2")
  .split(" ")
  .map(word => word.toLowerCase());

console.log(words); // ["user", "name", "info"]
JavaScript

この発想はとても重要です。単語配列を作る処理では、「分割そのもの」と「表記をそろえる処理」は別に考えると設計しやすくなります。

ステップ5:最後に空要素を取り除く

文字列の状態によっては、分割結果に空文字が混ざることがあります。たとえば連続記号や先頭末尾の区切りが原因です。

// 空文字が混ざる例
const input = "-user--name-";
const normalized = input.replace(/[-_]+/g, " ");
const words = normalized.split(" ");

console.log(words); // ["", "user", "name", ""]
JavaScript

このようなときは、filter() で空文字を取り除くときれいになります。

// 空文字を除去する例
const input = "-user--name-";
const normalized = input.replace(/[-_]+/g, " ");
const words = normalized
  .split(" ")
  .filter(word => word.length > 0);

console.log(words); // ["user", "name"]
JavaScript

実務では、この「不要な要素を最後に掃除する」処理が非常に役立ちます。途中で多少ゆるく変換しても、最後に配列を整えれば結果の品質を保ちやすくなります。

まずは基本版を作る

ここまでの考え方を踏まえて、まずはわかりやすい基本版を作ります。これは、空白・ハイフン・アンダースコアを区切りとして単語配列に変換するシンプルな関数です。

// 文字列を単語配列へ変換する基本版
function toWords(str) {
  return str
    // 1. 前後の空白を削除する
    .trim()
    // 2. ハイフンとアンダースコアを空白にそろえる
    .replace(/[-_]+/g, " ")
    // 3. 1個以上の空白で分割する
    .split(/\s+/);
}

// 動作確認
console.log(toWords("first name"));     // ["first", "name"]
console.log(toWords("first-name"));     // ["first", "name"]
console.log(toWords("first_name"));     // ["first", "name"]
console.log(toWords("  first   name ")); // ["first", "name"]
JavaScript

この段階でも、フォーム入力や簡単な識別子の処理には十分使えることがあります。ただし、まだ camelCase や null には対応していません。

実務で重要な注意点

null と undefined をどう扱うか

実務では、入力が必ず文字列とは限りません。null や undefined に対してそのまま trim() を呼ぶとエラーになります。

// これはエラーになる例
const value = null;
value.trim(); // TypeError
JavaScript

そのため、安全に使えるユーティリティにするなら、最初に入力チェックを入れるべきです。

// null / undefined を安全に扱う例
function toWordsSafe(value) {
  // null または undefined の場合は空配列を返す
  if (value == null) {
    return [];
  }

  return String(value)
    .trim()
    .replace(/[-_]+/g, " ")
    .split(/\s+/)
    .filter(word => word.length > 0);
}
JavaScript

ここで空文字ではなく空配列を返しているのは、「単語の集まり」を返す関数として自然だからです。返り値の型が安定していると、呼び出し側のコードが書きやすくなります。

記号をどこまで区切りとして扱うか

ここは実務でかなり重要です。たとえば、ドットやスラッシュを区切りとみなしたい場合もあれば、メールアドレスやURLのように、そのまま保持したい場合もあります。

たとえば次の文字列を見てください。

これらをすべて同じルールで機械的に分割すると、意図しない結果になることがあります。つまり、「何を区切りとみなすか」はデータの意味に依存します。

初心者の方はここを特に意識してください。便利そうだからといって、すべての記号を一律で区切り扱いにすると、別の用途で壊れやすくなります。業務では、対象データに合わせてルールを絞ることが大切です。

日本語をどう扱うか

日本語を含む文字列は少し厄介です。英語のように空白で単語が区切られないことが多いため、単純な split() では自然な単語分割ができません。

たとえば、次の2つは扱いやすさが違います。

  • "ユーザー 名" は空白で ["ユーザー", "名"] にできる
  • "ユーザー名" は単純なルールでは自然な分割が難しい

そのため、一般的な業務ユーティリティとしては、次のどちらかに割り切るのが現実的です。

  • 英数字中心の識別子やキー名だけを対象にする
  • 日本語は空白や記号がある場合だけ分割する

自然言語として日本語を本格的に単語分割したい場合は、単純な文字列ユーティリティの範囲を超えます。そこは無理にひとつの関数で全部解決しようとしないことが大切です。

数字を単語としてどう扱うか

数字を単語の一部として残すのか、別単語に切り出すのかも仕様ポイントです。

たとえば "version2File" を考えてみます。

  • ["version2", "file"] としたい場合
  • ["version", "2", "file"] としたい場合

どちらが正しいかは用途次第です。ファイル名や識別子なら前者で十分なことが多いですが、検索や解析では後者のほうが便利なこともあります。最初に仕様として決めるべき部分です。

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

ここでは、比較的多くの業務で使いやすい実務向けテンプレートを紹介します。この版では、null 安全、空白・ハイフン・アンダースコア・ドットなどの区切り対応、camelCase / PascalCase 対応、空要素除去、小文字正規化まで行います。

// 文字列を単語配列へ変換する実務向けテンプレート
function toWords(value) {
  // null または undefined の場合は空配列を返す
  if (value == null) {
    return [];
  }

  return String(value)
    // 1. 前後の空白を削除する
    .trim()
    // 2. camelCase / PascalCase の境目に空白を入れる
    .replace(/([a-z0-9])([A-Z])/g, "\$1 $2")
    // 3. 区切りとして扱いたい記号を空白にそろえる
    .replace(/[-_.\/]+/g, " ")
    // 4. 1個以上の空白で分割する
    .split(/\s+/)
    // 5. 空要素を除去する
    .filter(word => word.length > 0)
    // 6. 比較や再利用しやすいよう小文字にそろえる
    .map(word => word.toLowerCase());
}

// 動作確認
console.log(toWords("first name"));          // ["first", "name"]
console.log(toWords("first-name"));          // ["first", "name"]
console.log(toWords("first_name"));          // ["first", "name"]
console.log(toWords("firstNameInfo"));       // ["first", "name", "info"]
console.log(toWords("API.endpoint/url"));    // ["api", "endpoint", "url"]
console.log(toWords("  UserProfileData  ")); // ["user", "profile", "data"]
console.log(toWords(null));                  // []
JavaScript

このテンプレートの大事な点は、「変換の順番」です。前処理、単語境界の補完、区切り文字の統一、分割、後処理という流れで考えると、コードの意図がはっきりします。

処理の流れを具体例で追う

たとえば入力が " userProfile-data_v2 " のとき、どのように変換されるかを順番に見てみます。

変換の途中経過

  • 元の文字列:" userProfile-data_v2 "
  • trim() 後:"userProfile-data_v2"
  • camelCase 分割補完後:"user Profile-data_v2"
  • 記号の統一後:"user Profile data v2"
  • 分割後:["user", "Profile", "data", "v2"]
  • 小文字化後:["user", "profile", "data", "v2"]

このように、文字列を一発でうまく処理しようとするのではなく、少しずつ整形していくと考えるのがコツです。これは初心者に限らず、実務者にとっても非常に重要な思考法です。

例題で理解を固める

例題1:空白区切りの基本

// 例題1
console.log(toWords("apple orange banana"));
// ["apple", "orange", "banana"]
JavaScript

もっとも基本的なパターンです。複数単語を配列に変える土台になります。

例題2:ハイフンやアンダースコアを含むケース

// 例題2
console.log(toWords("user-name_info"));
// ["user", "name", "info"]
JavaScript

業務データでは、このような区切りの揺れは非常によくあります。実務向けユーティリティでは、こうした表記ゆれを吸収できることが価値になります。

例題3:camelCase のケース

// 例題3
console.log(toWords("userAccountStatus"));
// ["user", "account", "status"]
JavaScript

空白がないから1単語と決めつけないことが大切です。プログラム上の識別子には、この形式が頻繁に出てきます。

例題4:混在ケース

// 例題4
console.log(toWords("API-responseData_v2"));
// ["api", "response", "data", "v2"]
JavaScript

実務では、きれいな形式だけが来ることはむしろ少ないです。混在パターンにどれだけ強いかが、ユーティリティ関数の実用性を決めます。

テストをまとめて確認する方法

ユーティリティ関数は、1件動いたから安心ではありません。複数パターンをまとめて確認することが大切です。

// 代表的な入力パターンをテストする例
const testCases = [
  ["first name", ["first", "name"]],
  ["first-name", ["first", "name"]],
  ["first_name", ["first", "name"]],
  ["firstName", ["first", "name"]],
  ["  first   name  ", ["first", "name"]],
  ["API.endpoint/url", ["api", "endpoint", "url"]],
  ["userProfileData", ["user", "profile", "data"]],
  [null, []],
  [undefined, []],
  [12345, ["12345"]]
];

for (const [input, expected] of testCases) {
  const actual = toWords(input);

  // 配列を文字列化して簡単に比較する
  const pass = JSON.stringify(actual) === JSON.stringify(expected);

  console.log({
    input,
    expected,
    actual,
    pass
  });
}
JavaScript

初心者の方は、関数を書く練習と同じくらい、テストケースを書く練習を重視するのがおすすめです。むしろ実務では、何を入力して何を期待するかを先に言語化できる人のほうが強いです。

実務での活用例

検索キーワードの分割

ユーザーが入力した検索語を単語ごとに分けて扱いたい場面があります。

// 検索キーワードを単語配列へ変換する例
const query = "JavaScript utility function";
const keywords = toWords(query);

console.log(keywords); // ["javascript", "utility", "function"]
JavaScript

識別子の変換前処理

単語配列にできれば、その後に別の命名形式へ変換しやすくなります。

// 単語配列から snake_case を作る例
function toSnakeCase(value) {
  return toWords(value).join("_");
}

console.log(toSnakeCase("userProfileData")); // "user_profile_data"
JavaScript

このように、単語配列への変換は中間表現としてとても便利です。

CSVヘッダーの正規化

CSVや表形式データのヘッダーを扱いやすくしたいときにも役立ちます。

// CSVヘッダーを単語配列へ変換する例
const headers = ["First Name", "last-name", "AccountStatus"];
const splitHeaders = headers.map(toWords);

console.log(splitHeaders);
// [
//   ["first", "name"],
//   ["last", "name"],
//   ["account", "status"]
// ]
JavaScript

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

split() だけで何とかしようとしてしまう

split() は大切な基本ですが、実務ではそれだけでは足りないことが多いです。なぜなら、入力データはそこまで素直ではないからです。

そのため、初心者のうちから「分割の前に整える」という考え方を持つことが大切です。

  • 前後の空白を消す
  • 区切り文字をそろえる
  • camelCase の境界を補う
  • 最後に空要素を除去する

この順番で考えると、無理なく設計できます。

正規表現を一発で完璧に書こうとする

実務では、一発で全部解決する複雑な正規表現より、段階的に整えるコードのほうが保守しやすいことが多いです。初心者の段階では特に、短くても意味が読めないコードより、少し長くても意図が見えるコードを優先するほうがよいです。

入力データを信用してしまう

これは情報セキュリティや堅牢性の観点でも重要です。外部入力には想定外の値が来る前提で考えるべきです。null、空文字、過剰な空白、記号だらけの文字列、数値など、さまざまな値に対して関数がどう振る舞うかを意識すると、実務で壊れにくいコードになります。

小さなユーティリティ関数でも、この姿勢を身につけておくことが将来的に大きな差になります。

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

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

  • 入力は識別子なのか、自然文なのか
  • 区切りとして扱う記号は何か
  • camelCase や PascalCase に対応するか
  • 数字を単語として分離するか
  • 日本語を対象に含めるか
  • null や undefined の返り値をどうするか
  • 最終的に大文字化や小文字化が必要か

この確認を最初にしておくと、「とりあえず動くコード」ではなく、「業務要件に合ったコード」を書けるようになります。

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

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

/**
 * 値を単語配列へ変換する
 *
 * 仕様:
 * - null / undefined は空配列を返す
 * - camelCase / PascalCase に対応する
 * - 空白、ハイフン、アンダースコア、ドット、スラッシュを区切りとして扱う
 * - 空要素は除去する
 * - 最後に小文字へそろえる
 */
function toWords(value) {
  // null または undefined の場合は空配列を返す
  if (value == null) {
    return [];
  }

  return String(value)
    // 前後の空白を削除する
    .trim()
    // camelCase / PascalCase の境目に空白を入れる
    .replace(/([a-z0-9])([A-Z])/g, "\$1 $2")
    // 区切りとして扱いたい記号を空白に変換する
    .replace(/[-_.\/]+/g, " ")
    // 1個以上の空白で分割する
    .split(/\s+/)
    // 空文字を除去する
    .filter(word => word.length > 0)
    // 扱いやすいよう小文字へ統一する
    .map(word => word.toLowerCase());
}

// 使用例
console.log(toWords("userProfileData"));     // ["user", "profile", "data"]
console.log(toWords("API-response_v2"));     // ["api", "response", "v2"]
console.log(toWords("  first name  "));      // ["first", "name"]
console.log(toWords(null));                  // []
JavaScript

まとめ

JavaScriptで文字列を単語配列に変換する処理は、見た目以上に実務的な価値があります。これは単なる分割処理ではなく、入力データを扱いやすい形へ正規化するための重要な基礎です。

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

  • 最初に入力と出力の仕様を明確にすること
  • いきなり分割せず、前処理で区切りを整えること
  • camelCase など見えにくい単語境界も考慮すること
  • null や記号混在など、実務で起こる乱れを想定すること
  • 複数パターンをテストして挙動を確かめること

初心者の方は、まず「文字列を段階的に整えてから分割する」という考え方をしっかり身につけるのがおすすめです。この考え方は、単語配列への変換だけでなく、snake_case、camelCase、検索前処理、バリデーションなど、さまざまな場面に応用できます。

小さなユーティリティ関数でも、仕様を先に決め、防御的に書き、テストで確認する。この習慣こそが、業務で通用するJavaScript力につながります。

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