JavaScript Tips | 文字列ユーティリティ:整形 - 単語分割

JavaScript JavaScript
スポンサーリンク

なぜ「単語分割」ユーティリティが必要になるのか

キャメルケース化・スネークケース化・ケバブケース化・パスカルケース化。
ここまでいろいろやってきましたが、実は全部の“土台”にあるのが 「単語分割」 です。

"userNameId"
"user_name_id"
"user-name-id"
"user name id"

これらを「user」「name」「id」という“単語の配列”に分解できれば、
あとは「どうつなげ直すか」を変えるだけで、
キャメル・スネーク・ケバブ・パスカルに自由に変換できます。

だからこそ、「単語分割ユーティリティ」は
文字列整形系ユーティリティの“心臓部”と言っていい存在です。


単語分割でやりたいことを整理する

いろんな形式から「単語の配列」を取り出したい

業務でよく出てくる形式を並べてみます。

"userNameId"(キャメルケース)
"UserNameId"(パスカルケース)
"user_name_id"(スネークケース)
"user-name-id"(ケバブケース)
"user name id"(スペース区切り)

これらを全部、最終的にこうしたいわけです。

["user", "name", "id"]
JavaScript

つまり、「入力形式がバラバラでも、同じ“単語の配列”に落とし込む」のがゴールです。


単語分割の基本方針

やりたいことをもう少し細かく分解すると、こうなります。

前後の余計な空白を削る。
スペース・アンダースコア・ハイフンは「区切り」として扱う。
キャメルケース/パスカルケースでは「大文字の手前」で区切る。
全部いったん小文字にそろえておく(後で整形しやすくするため)。

このルールを一箇所にまとめたのが「単語分割ユーティリティ」です。


実装例:単語分割ユーティリティの基本形

コード全体

まずは、完成形を見てください。

function splitWords(value) {
  if (value == null) return [];

  const str = String(value).trim();

  if (str === "") return [];

  // 1. 区切り文字(スペース・アンダースコア・ハイフン)を統一
  const normalized = str.replace(/[\s_\-]+/g, " ");

  // 2. キャメルケース/パスカルケースの大文字の前にスペースを入れる
  const withSpaces = normalized
    .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
    .replace(/([A-Z])([A-Z][a-z])/g, "$1 $2");

  // 3. スペースで分割して、小文字にそろえる
  const words = withSpaces
    .split(" ")
    .map((w) => w.toLowerCase())
    .filter(Boolean);

  return words;
}
JavaScript

ここから、重要なポイントを順番に深掘りしていきます。


ステップ1:区切り文字を「スペース」に統一する

スネーク・ケバブ・スペースを一旦まとめる

最初のポイントはここです。

const normalized = str.replace(/[\s_\-]+/g, " ");
JavaScript

[\s_\-]+ は、

空白文字(スペース・タブ・改行など)
アンダースコア _
ハイフン -

が「1文字以上連続した部分」を意味します。

それを " "(半角スペース1つ)に置き換えています。

例えば:

"user_name-id""user name id"
" user__name---id "" user name id "

という感じです。

ここで大事なのは、
「いろんな区切り記号を“スペース1つ”に正規化している」ことです。
こうしておくと、後の処理が一気にシンプルになります。


ステップ2:キャメル/パスカルの「大文字の手前」にスペースを入れる

大文字を「単語の境目」として扱う

次のポイントがここです。

const withSpaces = normalized
  .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
  .replace(/([A-Z])([A-Z][a-z])/g, "$1 $2");
JavaScript

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

([a-z0-9])([A-Z])
小文字 or 数字の直後に大文字が来たら、その間にスペースを入れる。
例: "userName""user Name""user1Name""user1 Name"

([A-Z])([A-Z][a-z])
大文字が連続していて、そのあとに小文字が続くところで区切る。
例: "UserID""User ID""HTTPRequest""HTTP Request"

これを、さっきの「区切りをスペースに統一した文字列」に対して行うことで、

"userNameId""user Name Id"
"UserID""User ID"

のように、「単語の境目」にスペースを差し込んでいきます。

ここが キャメル/パスカルを“単語”として扱えるようにする一番重要な部分 です。


ステップ3:スペースで分割して、小文字にそろえる

最終的に「単語の配列」に落とし込む

最後の仕上げがここです。

const words = withSpaces
  .split(" ")
  .map((w) => w.toLowerCase())
  .filter(Boolean);
JavaScript

split(" ") でスペース区切りにして配列にする。
toLowerCase() で全部小文字にそろえる。
filter(Boolean) で空文字("")を取り除く。

これで、どんな形式の入力でも、
最終的に「小文字の単語配列」に変換できます。


具体例で動きを確認する

いろんな形式を同じ配列に落とし込む

splitWords("userNameId");      // ["user", "name", "id"]
splitWords("UserNameId");      // ["user", "name", "id"]
splitWords("user_name_id");    // ["user", "name", "id"]
splitWords("user-name-id");    // ["user", "name", "id"]
splitWords("  user  name id "); // ["user", "name", "id"]
splitWords("USER_ID");         // ["user", "id"]
JavaScript

形式がバラバラでも、
同じ配列 ["user", "name", "id"] にそろえられているのが分かると思います。

ここまで来れば、あとは

キャメルケース化 → 最初を小文字、2単語目以降の先頭を大文字にしてつなげる。
パスカルケース化 → 全部の先頭を大文字にしてつなげる。
スネークケース化 → _ でつなげる。
ケバブケース化 → - でつなげる。

という「再構成」の問題に変わります。


単語分割ユーティリティをどう活かすか

他の整形ユーティリティの“共通基盤”にする

例えば、キャメルケース化をこう書き換えられます。

function toCamelCase(value) {
  const words = splitWords(value);
  if (words.length === 0) return "";

  const [first, ...rest] = words;

  return (
    first +
    rest
      .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
      .join("")
  );
}
JavaScript

パスカルケース化ならこうです。

function toPascalCase(value) {
  const words = splitWords(value);
  if (words.length === 0) return "";

  return words
    .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
    .join("");
}
JavaScript

スネークケース化・ケバブケース化も同じように書けます。

「単語分割を一箇所にまとめる」ことで、
他の整形ユーティリティがシンプルかつ一貫した動きになる

ここが、業務コードとしてめちゃくちゃ大事なポイントです。


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

「まず単語に分ける」という発想を持つ

文字列整形でいきなり

「大文字を小文字にして…」
「アンダースコアをハイフンにして…」

とやり始めると、だいたい途中でぐちゃぐちゃになります。

そうではなくて、

「まず単語に分ける」 → 「どうつなげ直すかを決める」

という二段構えで考える癖をつけると、
処理の見通しが一気に良くなります。

単語分割ユーティリティは、その「最初の一段目」を担う存在です。


小さな練習で感覚をつかむ

ブラウザのコンソールで、いろいろ試してみてください。

splitWords("userName");
splitWords("UserNameId");
splitWords("user_name_id");
splitWords("user-name-id");
splitWords("  USER  NAME  ID  ");
splitWords(null);
JavaScript

全部が「小文字の単語配列」に落ちていくのを確認してみてください。

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

export function splitWords(value) { ... }
JavaScript

を一つ置いて、
「命名変換系のユーティリティは、必ず最初に splitWords を通る」
というルールにしてみてください。

それができた瞬間、あなたの文字列整形は
「場当たり的な置換の寄せ集め」から
「単語分割 → 再構成」という、筋の通った設計に変わります。

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