JavaScript Tips | 文字列操作:CONSTANT_CASEに変換する

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

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

JavaScriptで文字列を CONSTANT_CASE に変換する処理は、業務開発でとてもよく使います。たとえば、設定キー、環境変数名、定数名、CSVヘッダーの正規化、外部データのキー統一などで役立ちます。

CONSTANT_CASE とは、単語をアンダースコアでつなぎ、全体を大文字にした形式です。たとえば userName を USER_NAME に、api endpoint url を API_ENDPOINT_URL に変換したものです。

一見すると単純そうに見えますが、実務では空白、ハイフン、camelCase、PascalCase、連続記号、日本語、null や undefined など、さまざまな入力を考慮する必要があります。そのため、ただ大文字にするだけでは足りません。入力の揺れをどこまで吸収するかを最初に決め、その仕様に沿って処理を組み立てることが大切です。

まず押さえたい:CONSTANT_CASE とは何か

CONSTANT_CASE は、主に「変更されない値」や「共通ルールで管理したい識別子」を扱う場面で使われます。JavaScriptそのものが定数名にこの形式を強制するわけではありませんが、実務では広く使われる命名スタイルです。

  • 定数名:MAX_RETRY_COUNT
  • 環境変数:DATABASE_URL
  • 設定キーの統一:DEFAULT_THEME_COLOR
  • 外部入力の正規化:USER_ID、ORDER_STATUS

この形式を使うメリットは、単語の区切りが見やすく、定数であることがひと目でわかりやすいことです。また、データのキー名に統一ルールがあると、保守やレビューもしやすくなります。

最初に決めるべきこと:入力と出力の仕様

初心者のうちほど重要なのが、いきなりコードを書かずに「どんな入力を、どういう出力にするか」を先に決めることです。ここを曖昧にすると、あとで例外処理がどんどん増え、コードが読みにくくなります。

たとえば、次のような入力をどう扱うかを事前に決めます。

  • "user name" → USER_NAME
  • "user-name" → USER_NAME
  • "userName" → USER_NAME
  • "UserName" → USER_NAME
  • " user name " → USER_NAME
  • "user__name" → USER_NAME にするのか、そのままにするのか
  • null や undefined は空文字にするのか、エラーにするのか
  • 日本語 "ユーザー名" を許可するのか

実務では、この「仕様決め」が品質に直結します。関数を書く前に、少なくとも代表的な入力例を5個から10個ほど並べる習慣をつけると、かなり堅い実装になります。

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

ここからは、文字列を CONSTANT_CASE に変換する流れを、できるだけわかりやすく順番に見ていきます。

ステップ1:前後の余分な空白を取り除く

ユーザー入力やCSVデータ、フォーム値には、前後に不要な空白が入っていることがよくあります。このまま処理すると、意図しないアンダースコアが付いたり、比較処理でズレたりします。

そこで最初に trim() を使って、前後の空白を削除します。

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

console.log(trimmed); // "user name"
JavaScript

この一手間は地味ですが、とても重要です。実務では「とりあえず最初に整える」前処理が、後ろの処理をかなり簡単にしてくれます。

ステップ2:単語の区切りをそろえる

CONSTANT_CASE では単語の区切りをアンダースコアに統一します。しかし入力は、空白区切りだったり、ハイフン区切りだったり、複数スペースだったりします。

そのため、まずは「区切りになりそうなもの」をアンダースコアにそろえる発想が必要です。

// 空白やハイフンをアンダースコアに統一する例
const input = "user-name test";
const normalized = input.replace(/[\s-]+/g, "_");

console.log(normalized); // "user_name_test"
JavaScript

ここで使っている正規表現 /[\s-]+/g は、次の意味です。

  • \s は空白文字を表します
  • - はハイフンを表します
  • [...] は「この中のどれか1文字」を表します
  • + は「1回以上の繰り返し」です
  • g は「見つかったすべてを置換する」です

つまり、空白やハイフンが1文字でも複数でも続いていたら、まとめて _ に置き換える、という意味です。

ステップ3:camelCase や PascalCase の区切りを見つける

実務では userName や UserName のような形式もよく入力されます。これらは空白もハイフンもないので、ステップ2だけでは USERNAME になってしまい、単語の区切りが失われます。

そこで「小文字または数字の直後に大文字が来たら、そこが単語の切れ目だ」と判断して、間にアンダースコアを入れます。

// camelCase や PascalCase の区切りにアンダースコアを入れる例
const input = "userName";
const separated = input.replace(/([a-z0-9])([A-Z])/g, "\$1_\$2");

console.log(separated); // "user_Name"
JavaScript

この正規表現 /([a-z0-9])([A-Z])/g は、次のように読めます。

  • ([a-z0-9]) は小文字または数字を1文字つかまえます
  • ([A-Z]) はその直後の大文字を1文字つかまえます
  • $1_$2 は「前半 + アンダースコア + 後半」に置き換える意味です

たとえば userName は rN の部分がマッチし、user_Name になります。

この処理はとても重要です。なぜなら、業務データには人が手で入力した文字列だけでなく、別システム由来のキー名やAPIのレスポンス名が混ざるからです。区切り方が統一されていないデータをどう吸収するかが、ユーティリティ関数の価値になります。

ステップ4:最後に大文字へ変換する

区切りを整えたら、最後に全体を大文字へ変換します。ここで toUpperCase() を使います。

// 全体を大文字に変換する例
const input = "user_name";
const upper = input.toUpperCase();

console.log(upper); // "USER_NAME"
JavaScript

この順番も大切です。先に大文字化してしまうと、camelCase の境目を見つけにくくなる場合があります。そのため、一般には「区切りを整えてから大文字化する」ほうが扱いやすいです。

まずは基本版を作る

ここまでの考え方をまとめると、基本版の関数は次のようになります。

// 文字列を CONSTANT_CASE に変換する基本版
function toConstantCase(str) {
  return str
    // 1. 前後の空白を削除する
    .trim()
    // 2. camelCase / PascalCase の区切りにアンダースコアを入れる
    .replace(/([a-z0-9])([A-Z])/g, "\$1_$2")
    // 3. 空白やハイフンをアンダースコアに統一する
    .replace(/[\s-]+/g, "_")
    // 4. 全体を大文字に変換する
    .toUpperCase();
}

// 動作確認
console.log(toConstantCase("userName"));       // "USER_NAME"
console.log(toConstantCase("UserName"));       // "USER_NAME"
console.log(toConstantCase("user name"));      // "USER_NAME"
console.log(toConstantCase("user-name"));      // "USER_NAME"
console.log(toConstantCase("  api endpoint ")); // "API_ENDPOINT"
JavaScript

この基本版でもかなり実用的です。ただし、実務ではこれだけだとまだ不十分なことがあります。

実務で重要になる注意点

null や undefined をどう扱うか

実務コードでは、必ずしも入力がきれいな文字列とは限りません。フォーム値、APIレスポンス、CSV解析結果、設定ファイルなどから値が来ると、null や undefined が混ざることがあります。

この状態でいきなり trim() を呼ぶとエラーになります。

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

そのため、防御的に書くなら、最初に文字列化するか、文字列以外を弾く必要があります。

// null や undefined を安全に扱う例
function toConstantCaseSafe(str) {
  // null または undefined の場合は空文字を返す
  if (str == null) {
    return "";
  }

  return String(str)
    .trim()
    .replace(/([a-z0-9])([A-Z])/g, "\$1_$2")
    .replace(/[\s-]+/g, "_")
    .toUpperCase();
}
JavaScript

str == null は、null と undefined の両方をまとめて判定したいときによく使われます。初心者のうちは「なぜ === null ではないのか」と感じるかもしれませんが、この用途では便利な書き方です。

連続アンダースコアの整理

入力によっては、すでにアンダースコアが入っていたり、空白とハイフンが混ざっていたりして、結果としてアンダースコアが連続することがあります。

たとえば次のようなケースです。

  • "user__name"
  • "user - name"
  • " user --- name "

これをそのままにすると、見た目や統一性が崩れます。そのため、連続するアンダースコアを1個にまとめる処理を入れることが多いです。

// 連続するアンダースコアを1個にまとめる例
const input = "user___name";
const normalized = input.replace(/_+/g, "_");

console.log(normalized); // "user_name"
JavaScript

先頭と末尾のアンダースコアを除去する

置換の過程によっては、先頭や末尾にアンダースコアが残る場合があります。たとえば、記号を区切りとしてまとめて処理したときなどです。

こうした余分なアンダースコアは、最終的に取り除くと見た目が整います。

// 先頭と末尾のアンダースコアを削除する例
const input = "_user_name_";
const cleaned = input.replace(/^_+|_+$/g, "");

console.log(cleaned); // "user_name"
JavaScript

^ は文字列の先頭、$ は文字列の末尾を表します。つまりこの正規表現は、「先頭の連続アンダースコア」または「末尾の連続アンダースコア」を削除しています。

英数字以外をどう扱うか

ここは実務で特に重要です。なぜなら、どこまで許可するかで仕様が大きく変わるからです。

たとえば、記号をどうするかを決める必要があります。

  • "user.name" を USER_NAME にするのか
  • "price(税込)" をどう扱うのか
  • "error#code" を ERROR_CODE にするのか

業務用途では、英数字以外は区切りとみなしてアンダースコアに寄せるほうが扱いやすいことが多いです。ただし、用途によっては日本語や一部記号を残したいこともあります。

このため、「何を残して、何を落とすか」は先に決める必要があります。ユーティリティ関数は便利ですが、曖昧なまま万能にしようとすると、逆に使いにくくなります。

日本語を含む場合の考え方

日本語を含む文字列を CONSTANT_CASE にしたいケースもあります。ただし、英語圏の命名規則を前提にした処理なので、日本語に対しては期待どおりに「単語境界」を判定しにくいです。

たとえば "ユーザー 名" なら空白で区切れますが、"ユーザー名" のように連続した日本語から自然な単語分割をするのは、通常の簡単な正規表現では困難です。

そのため、日本語を含む入力では次のどちらかに寄せるのが現実的です。

  • 日本語はそのまま残し、区切りだけ整える
  • 英数字ベースの識別子のみを対象にし、日本語入力は別ルールにする

実務では後者のほうが安全です。識別子や設定キーに使うなら、入力段階で英数字に制限する設計のほうがトラブルを減らせます。

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

ここまでの注意点を踏まえて、実務で比較的使いやすいテンプレートを示します。これは「できるだけ入力の揺れを吸収して、きれいな CONSTANT_CASE を返す」ことを目的にした例です。

// 文字列を実務向けに CONSTANT_CASE へ変換する関数
function toConstantCase(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(/[^a-zA-Z0-9]+/g, "_")
    // 4. 連続するアンダースコアを1個にまとめる
    .replace(/_+/g, "_")
    // 5. 先頭と末尾のアンダースコアを削除する
    .replace(/^_+|_+$/g, "")
    // 6. 最後に大文字へ変換する
    .toUpperCase();
}

// 動作確認用の例
console.log(toConstantCase("userName"));             // "USER_NAME"
console.log(toConstantCase("UserName"));             // "USER_NAME"
console.log(toConstantCase("user name"));            // "USER_NAME"
console.log(toConstantCase("user-name"));            // "USER_NAME"
console.log(toConstantCase("  user---name  "));      // "USER_NAME"
console.log(toConstantCase("api.endpoint url"));     // "API_ENDPOINT_URL"
console.log(toConstantCase("error#code"));           // "ERROR_CODE"
console.log(toConstantCase("__already__ok__"));      // "ALREADY_OK"
console.log(toConstantCase(null));                   // ""
console.log(toConstantCase(undefined));              // ""
console.log(toConstantCase(12345));                  // "12345"
JavaScript

このテンプレートの重要ポイントは、「正規化の順番」が整理されていることです。実務では1個1個の正規表現よりも、処理の順番のほうが品質に効きます。

  • 最初に前後のノイズを落とす
  • 次に単語境界を補う
  • その後に区切り記号を統一する
  • 最後に見た目を整える

この順番で考えると、コードの意図が読みやすくなり、あとで保守しやすくなります。

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

たとえば入力が " userName-test value " だったとします。この文字列がどのように変換されるかを順番に見てみます。

変換の途中経過

  • 元の文字列:" userName-test value "
  • trim() 後:"userName-test value"
  • camelCase区切り追加後:"user_Name-test value"
  • 記号・空白をアンダースコア化後:"user_Name_test_value"
  • 大文字化後:"USER_NAME_TEST_VALUE"

このように、いきなり完成形を作るのではなく、「文字列を少しずつ整形していく」と考えると理解しやすくなります。

例題で理解を固める

例題1:基本的な変換

次の入力を CONSTANT_CASE に変換してみます。

// 例題1
console.log(toConstantCase("first name")); // "FIRST_NAME"
JavaScript

空白区切りをアンダースコアに変え、最後に大文字化しています。もっとも基本的なパターンです。

例題2:camelCase の変換

// 例題2
console.log(toConstantCase("firstName")); // "FIRST_NAME"
JavaScript

ここでは tN の位置を単語の境目として検出できるかがポイントです。単に大文字にするだけでは FIRSTNAME になってしまうため、境界の補完が必要です。

例題3:記号が混ざるケース

// 例題3
console.log(toConstantCase("user.id#main")); // "USER_ID_MAIN"
JavaScript

実務では、ドットやシャープなどが混ざる入力は珍しくありません。こうした記号を「区切り」としてまとめて処理できると、かなり便利です。

例題4:すでに近い形の文字列

// 例題4
console.log(toConstantCase("USER_NAME")); // "USER_NAME"
JavaScript

すでに理想形に近い入力が来ても、大きく壊さずにそのまま返せるのがよいユーティリティ関数です。こういう性質を「冪等的に近い」と考えるとよいです。つまり、何度通しても大きく崩れないことが大切です。

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

関数は「たまたま1件動いた」だけでは不十分です。実務では、複数のパターンをまとめて確認する習慣がとても重要です。

// 代表的な入力と期待値をまとめてテストする例
const testCases = [
  ["userName", "USER_NAME"],
  ["UserName", "USER_NAME"],
  ["user name", "USER_NAME"],
  ["user-name", "USER_NAME"],
  [" user---name ", "USER_NAME"],
  ["api.endpoint url", "API_ENDPOINT_URL"],
  ["error#code", "ERROR_CODE"],
  ["__already__ok__", "ALREADY_OK"],
  [null, ""],
  [undefined, ""],
  [12345, "12345"]
];

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

  // 結果を比較して表示する
  console.log({
    input,
    expected,
    actual,
    pass: actual === expected
  });
}
JavaScript

このように「入力」「期待値」「実際の結果」をセットで確認すると、仕様漏れやバグに気づきやすくなります。初心者の段階から、コードを書くことと同じくらいテストケースを並べることを大事にすると、成長が速くなります。

実務での活用例

環境変数名の生成

設定項目名から環境変数名を作る場面はよくあります。

// 設定キーから環境変数名を作る例
const settingKey = "databaseUrl";
const envName = toConstantCase(settingKey);

console.log(envName); // "DATABASE_URL"
JavaScript

CSVヘッダーの正規化

CSVファイルの列名は、人によって書き方がバラバラになりがちです。そのため、読み込み時に正規化しておくと、後続処理が安定します。

// CSVヘッダーを正規化する例
const headers = ["First Name", "last-name", "EmailAddress"];
const normalizedHeaders = headers.map(toConstantCase);

console.log(normalizedHeaders);
// ["FIRST_NAME", "LAST_NAME", "EMAIL_ADDRESS"]
JavaScript

オブジェクトキーの統一

外部APIや複数の入力元からデータを集める場合、キーの形式が統一されていないことがあります。そんなときに変換関数を使うと、扱いやすくなります。

// オブジェクトのキーを CONSTANT_CASE に統一する例
function normalizeObjectKeys(obj) {
  const result = {};

  for (const key in obj) {
    // 元のキーを CONSTANT_CASE に変換して代入する
    result[toConstantCase(key)] = obj[key];
  }

  return result;
}

const input = {
  firstName: "Taro",
  "last-name": "Yamada",
  "email address": "[email protected]"
};

console.log(normalizeObjectKeys(input));
/*
{
  FIRST_NAME: "Taro",
  LAST_NAME: "Yamada",
  EMAIL_ADDRESS: "[email protected]"
}
*/
JavaScript

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

正規表現だけを見て理解しようとしてしまう

初心者の方は、正規表現の記号だけを細かく追って混乱しがちです。しかし大事なのは、先に「何をしたいか」を言葉で整理することです。

  • 前後の空白を消したい
  • 単語の区切りをそろえたい
  • camelCase の境目を見つけたい
  • 最後に大文字へ変えたい

この日本語の設計図が先にあれば、正規表現はそれを実現する部品として理解しやすくなります。

一発で完璧な変換を目指してしまう

実務では、最初から万能な関数を作る必要はありません。むしろ、対象となるデータの実態に合わせて少しずつ育てるほうが安全です。

たとえば、最初は次の範囲だけ対応すれば十分かもしれません。

  • 空白
  • ハイフン
  • camelCase

その後、必要に応じて記号や日本語対応を足していけばよいです。最初から全部やろうとすると、かえって仕様がぶれやすくなります。

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

実務で特に大切なのはここです。外から入ってくる値は、きれいだと思わないことです。余分な空白、想定外の記号、数値、null、空文字など、何でも来る前提で考えるとコードが強くなります。

これは情報セキュリティや堅牢性の観点でも重要です。文字列変換そのものは小さな処理でも、入力を無条件に信用する癖がつくと、別の場面で脆さにつながります。ユーティリティ関数こそ、防御的に書く習慣を身につける練習に向いています。

より実務的に考えるための判断基準

CONSTANT_CASE 変換は、単なる見た目の整形ではありません。業務では「どの文字を同一視するか」「何を不正入力とみなすか」を決める設計作業でもあります。

そのため、実装前に次の観点を確認するのがおすすめです。

  • 入力は必ず文字列なのか
  • 数値を受け取る可能性はあるのか
  • 日本語や記号を許可するのか
  • 空文字を許すのか
  • 不正値は空文字にするのか、例外にするのか
  • 既存データとの互換性は必要か

この確認をしておくと、「変換できれば正しい」ではなく「業務要件に合っているから正しい」という判断ができるようになります。

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

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

/**
 * 値を CONSTANT_CASE に変換する
 * 
 * 仕様:
 * - null / undefined は空文字を返す
 * - camelCase / PascalCase に対応する
 * - 空白、ハイフン、各種記号はアンダースコアとして扱う
 * - 連続アンダースコアは1つにまとめる
 * - 先頭末尾のアンダースコアは削除する
 * - 最後に大文字へ変換する
 */
function toConstantCase(value) {
  // null / undefined は空文字にする
  if (value == null) {
    return "";
  }

  return String(value)
    // 前後の空白を削除する
    .trim()
    // camelCase / PascalCase の区切りを補う
    .replace(/([a-z0-9])([A-Z])/g, "\$1_\$2")
    // 英数字以外を区切りとしてアンダースコア化する
    .replace(/[^a-zA-Z0-9]+/g, "_")
    // 連続するアンダースコアを1つにまとめる
    .replace(/_+/g, "_")
    // 先頭と末尾のアンダースコアを削除する
    .replace(/^_+|_+$/g, "")
    // 全体を大文字へ変換する
    .toUpperCase();
}

// 使用例
console.log(toConstantCase("userName"));              // "USER_NAME"
console.log(toConstantCase("API endpoint url"));      // "API_ENDPOINT_URL"
console.log(toConstantCase("  error-code#main  "));   // "ERROR_CODE_MAIN"
console.log(toConstantCase(null));                    // ""
JavaScript

まとめ

JavaScriptで文字列を CONSTANT_CASE に変換する処理は、見た目以上に実務的な価値があります。単に大文字とアンダースコアへ変えるだけではなく、入力の揺れをどこまで吸収するかを設計することが重要です。

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

  • 最初に入力と出力の仕様を決めること
  • 前処理、区切り補完、記号統一、大文字化の順で考えること
  • null や記号混在など、実務で起きる入力の乱れを想定すること
  • 代表的なテストケースを最初から用意すること

初心者のうちは、正規表現そのものよりも「文字列を段階的に整えていく」という考え方を身につけることが重要です。この考え方は snake_case、kebab-case、入力正規化、検索用前処理などにもそのまま応用できます。

つまり、今回のテーマは単なる小技ではなく、実務で通用する文字列処理の基礎そのものです。小さなユーティリティ関数でも、仕様を明確にし、防御的に書き、テストで確かめる。この姿勢が、読みやすく壊れにくいコードにつながります。

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