大文字小文字変換

様々なテキストケーススタイルに変換

大文字
-
小文字
-
タイトルケース
-
文章ケース
-
キャメルケース
-
パスカルケース
-
スネークケース
-
ケバブケース
-
定数ケース
-

Unicode のケースマッピングは単純な A↔Z の置換ではない

ASCII は大文字と小文字を完全な双方向マッピングのように見せてきました。A–Z と a–z が正確に対応するため、大文字化・小文字化は可逆に思えます。Unicode はこのモデルを意図的に壊します。標準の SpecialCasing.txt は 1 対多、ロケール依存、文脈依存のマッピングを定義しており、JavaScript の toUpperCase() / toLowerCase() はそれを忠実に実装しています — つまり、この落とし穴は本番コードで顕在化します。 ドイツ語のエスツェット(ß)は 1 対多の代表例です。'ß'.toUpperCase() は 'SS' を返すため、出力が入力より長くなります。大文字の ẞ(U+1E9E)は 2008 年に Unicode へ追加され、2017 年からドイツ語正書法でも公式に認められましたが、デフォルトのマッピングは今も SS を返します。その結果 'straße'.toUpperCase().toLowerCase() は 'strasse' になり、往復変換で元の綴りが失われます。 トルコ語とアゼルバイジャン語は点付きの i と点なしの ı を区別します。トルコ語ロケールでは 'i'.toLocaleUpperCase('tr') が 'İ'(U+0130)を、'I'.toLocaleLowerCase('tr') が 'ı'(U+0131)を返します。一方、デフォルトロケールで 'İ'.toLowerCase() を呼ぶと 'i' に結合用の上点(U+0307)が付いた文字列が返り、.length は 2 になります。これが有名な Turkish-I バグ群です — 設定キーやプロトコルトークンを小文字化するソフトウェアは、デフォルトロケールがトルコ語のマシンで動いた瞬間に壊れます。 ギリシャ語は文脈依存性を持ち込みます。大文字の Σ は語中では σ に、語末では ς に小文字化されます(Unicode の Final_Sigma 規則)。JavaScript もこの規則を適用します。ここから導かれる実務ルール: lower(upper(x)) === x を仮定しない、ケース変換で長さが保存されると仮定しない、セキュリティに関わる正規化に単純なケース変換を使わない。
'ß'.toUpperCase()             // 'SS' — one char in, two out
'straße'.toUpperCase()
  .toLowerCase()              // 'strasse' — ß never comes back

'i'.toLocaleUpperCase('tr')   // 'İ' (U+0130, dotted capital I)
'I'.toLocaleLowerCase('tr')   // 'ı' (U+0131, dotless i)
'İ'.toLowerCase().length      // 2 — 'i' + combining dot (U+0307)

'ΣΟΦΟΣ'.toLowerCase()         // 'σοφος' — medial σ, final ς

単語はどこで終わるのか — 境界検出と頭字語のルール

どんなケース変換ツールも、まず最初に一つの問いに答える必要があります: 単語とは何か? アンダースコア、ハイフン、スペースでの分割は簡単です。難しいのは大文字が連続する camelCase 入力です。大文字が現れるたびに新しい単語を始める素朴なルールは、parseHTMLDocument を parse / H / T / M / L / Document に切り刻んでしまいます。まともなトークナイザは 2 つのルールを使います: 小文字→大文字の遷移で新しい単語を開き、大文字の連続の中では、直後に小文字が続く最後の大文字で新しい単語を開く — こうして parse / HTML / Document が得られます。 数字は本質的に曖昧です。v2Response は v2 / Response でしょうか、v / 2 / Response でしょうか? base64Encode は base64 / Encode か base / 64 / Encode か? 普遍的な正解はありません。ほとんどの変換器は数字を直前の単語にくっつけます。だからこそ user_id_2 と user_id2 は同じ camelCase 出力に潰れがちです。 機械的なルール同士が食い違うからこそ、スタイルガイドは頭字語について明確な立場を取りました。Google Java Style Guide は頭字語を普通の単語として扱います: XMLHTTPRequest ではなく XmlHttpRequest、newCustomerID ではなく newCustomerId。Swift API Design Guidelines は位置に応じて頭字語を一様に大文字化・小文字化することを要求します — 名前の先頭なら utf8Bytes、途中なら userSMTPServer。Go は逆の道を選びました: golint は正準表記を保つべき initialism のハードコードされたリスト(ID、URL、HTTP、API、JSON など約 40 個)を持ち、慣用的な Go は userID や ServeHTTP と書きます。つまり同じフレーズでも「正しい」camelCase はエコシステムごとに異なります。変換器にできるのは、一つのポリシーを選んで一貫して適用することだけです。

ケース変換は不可逆 — 往復しても元には戻らない

命名規則間の変換は情報を破壊します。どの情報が失われるのかを正確に知っておく価値があります。多くの変換器は入力を正規化された単語リスト(canonical word list)— 小文字の単語列、区切り文字は破棄 — に落とし込み、それを目的のスタイルで組み直します。同じ単語リストを生む 2 つの入力は、その時点で永久に区別不能になります。 最初の犠牲者は単語内部の大文字です。HTML_parser は camelCase では htmlParser になり、逆変換すると html_parser が返ってきます — HTML が元々大文字だったという記録はどこにも残りません。2 つ目は数字の境界です。user_id_2 は userId2 になり、逆変換は user_id2 を出力します。数字には区切りがどこにあったかを示すケース情報がないからです。3 つ目は先頭の区切り文字です。Python で内部メンバーを意味する慣習の _private は camelCase では private になり、意味を担う接頭辞が消えます。Python の name mangling を引き起こす二重アンダースコアも同様です。連続する区切り文字(a__b)は 1 つに潰れます。 エンジニアリング上の結論: 名前を再導出してはいけません。レイヤー間で識別子をマッピングするコードジェネレータ — ORM のカラムとフィールド、protobuf メッセージと JSON — は、往復変換を信用する代わりに元の名前を派生名と一緒に保存します。Protocol Buffers はまさにそうしています: すべてのフィールドは明示的な json_name を持つため、非可逆な変換が API の一部を静かに改名することはありません。
user_id_2   → camelCase  → userId2
userId2     → snake_case → user_id2      // '_2' boundary lost

HTML_parser → camelCase  → htmlParser
htmlParser  → snake_case → html_parser   // HTML capitals lost

_private    → camelCase  → private       // leading '_' lost
a__b        → camelCase  → aB            // double separator collapsed

好みではなく仕様がケースを強制する場面

命名規則はふつう社会的な合意にすぎませんが、いくつかのシステムはケースを強制ルールにしています。HTTP のヘッダーフィールド名は RFC 9110 により大文字小文字を区別せず、HTTP/2 と HTTP/3 はさらに踏み込んで、ワイヤ上ではフィールド名が小文字であることを要求します — モダンなプロキシが Content-Type ではなく content-type を表示するのはこのためです。環境変数は POSIX システムでは大文字小文字を区別し(PATH と path は共存できる)、大文字が慣習です。一方 Windows では区別されず、クロスプラットフォームなスクリプトの相互運用の罠になります。 CSS カスタムプロパティは大文字小文字を区別します(--Main-Color と --main-color は別の変数)。HTML の属性名やタグ名は区別しないにもかかわらず、です。カスタム要素名は小文字でハイフンを含まなければなりません(my-widget)— これはスタイルではなく HTML 仕様です。npm は 2017 年以降、新規パッケージ名の大文字を拒否します。JSONStream のような既存の混在ケースのパッケージは既得権として残っています。 データベースは引用符なしの識別子を正反対の方向に折りたたみます(folding): PostgreSQL は小文字へ、Oracle は大文字へ — どちらも SQL 標準を根拠に。Postgres で引用符付きの "UserAccounts" としてテーブルを作ると、以後すべてのクエリで永遠に引用符が必要になり、そのスキーマを Oracle に移すと折りたたみの向きが反転します。 最後の罠はファイルシステムです。macOS の APFS と Windows の NTFS はデフォルトで大文字小文字非区別(ただし保存はする)、Linux の ext4 は区別します。button.tsx に解決される import './Button' はすべての開発マシンで動き、Linux の CI でだけ失敗します — 「自分のマシンでは動く」の最も確実な発生源のひとつです。

命名規則をまたぐリファクタリングの実践ワークフロー

ドメイン概念をひとつリネームするというのは、すべての命名規則を同時に追いかけるということです: TypeScript の userAccount、SQL と Python の user_account、CSS クラスと URL の user-account、環境変数の USER_ACCOUNT、クラス名の UserAccount。1 つの変形だけ検索しても使用箇所の一部しか見つかりません。信頼できるワークフローは、まずすべての変形を生成し(このツールならペースト 1 回で済みます)、alternation でまとめて検索し — ripgrep なら 1 パスで完了 — 何かを置換する前にヒットをレビューすることです。 置換そのものは IDE の支援で安全になります。JetBrains の「Preserve case」置換オプションと VS Code の preserve-case トグル(置換ボックスの AB ボタン)は、userAccount→memberProfile と UserAccount→MemberProfile を一度の操作で処理するので、5 回に分けて置換する必要はありません。 API 境界では、そもそも手で変換しないでください。ワイヤフォーマットは snake_case が一般的で(Stripe、大半の Python / Ruby バックエンド)、JS クライアントは camelCase を期待します。シリアライゼーション層で宣言されたポリシーとして一度だけ変換しましょう — Rust なら serde の rename_all = "camelCase"、Java なら Jackson の PropertyNamingStrategies.SNAKE_CASE、Node なら camelcase-keys。注意点がひとつ: キーの深い変換は、キーが識別子ではなくデータであるマップをスキップしなければなりません — 外部 ID をキーとする辞書をケース変換すると、データが静かに壊れます。
# Find every variant of "user account" in one ripgrep pass
rg -n '(userAccount|UserAccount|user_account|user-account|USER_ACCOUNT)'

# Rust: convert once at the serialization boundary
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct UserAccount {
    user_id: u64,          // wire: "userId"
    display_name: String,  // wire: "displayName"
}
最終更新:

ツールについて

ケース変換ツールはテキストを camelCase / PascalCase / snake_case / kebab-case / CONSTANT_CASE などの命名規則に変換します。JavaScript は camelCase、Python は snake_case、CSS は kebab-case、環境変数は CONSTANT_CASE と慣習が異なるため、手作業より安全に切り替えできます。

使い方

  1. Type or paste the text you want to convert into the input box.
  2. All conversion variants render simultaneously in the results grid.
  3. Find the case style you need (camelCase, kebab-case, etc.) in the appropriate card.
  4. Click Copy on that card to put the result on your clipboard.
  5. Paste it into your IDE, terminal, config file, or commit message.

主な使用例

  • Renaming a database column (snake_case) into a TypeScript field (camelCase).
  • Generating CSS class names (kebab-case) from a design token name.
  • Converting JSON keys to match a different language convention during API integration.
  • Producing CONSTANT_CASE keys for .env files from a human-readable label.
  • Quickly producing a PascalCase class name from a feature description in a ticket.
  • Normalizing inconsistent variable names during a refactor.

よくある質問

Q. What is the difference between camelCase and PascalCase?

A. Both join words without separators, but camelCase keeps the first letter lowercase (myVariable) while PascalCase capitalizes it (MyClass). PascalCase is conventionally reserved for classes, types, and components.

Q. How do you handle acronyms like URL or ID?

A. Modern style guides (Google, Microsoft) treat acronyms as single words: parseUrl, userId. The converter follows that rule for predictable round-trip conversions.

Q. Will the tool guess word boundaries from a CONSTANT_CASE input?

A. Yes. It splits on underscores, hyphens, spaces, and case transitions, so HELLO_WORLD, helloWorld, and hello-world all produce the same canonical word list before re-joining.

Q. Does conversion work with non-English characters?

A. Yes for case-insensitive scripts. Languages without case (Korean, Japanese, Chinese) keep their characters intact and only the separators are adjusted.