キャメルケース(camelCase)は、空白を使わずに単語をつなげ、2 語目以降の先頭を大文字にする書き方です。MDN の用語集は「大文字がラクダの背中のこぶに似ていることから名づけられました」と説明しています(MDN: Camel case)。lastUpdateTime のように英単語を小文字で書く限りは迷いません。迷うのは URI や ID のような略語、base64 のような数字入りの語、そして既存の名前を別の書き方に変換するときです。
この記事では、キャメルケースの 2 つの種類、隣で使われるスネークケースやケバブケースとの使い分け、各言語の公式規約、略語の扱い、日本語環境ならではの落とし穴を順に見ます。変換結果はすべて本サイトのテキストケース変換で実際に出したものです。
ローワーキャメルケースとアッパーキャメルケース
キャメルケースには、先頭の 1 文字だけが違う 2 種類があります。
| 呼び方 | 別名 | 先頭 | 例 |
|---|---|---|---|
| ローワーキャメルケース | 小文字キャメルケース、camelCase | 小文字 | lastUpdateTime |
| アッパーキャメルケース | パスカルケース、PascalCase | 大文字 | LastUpdateTime |
日本語の記事や社内規約で単に「キャメルケース」と書かれている場合は、ローワーのほうを指すことが多いものの、決まりではありません。MDN も「フレーズ全体の最初の文字が大文字の場合、大文字キャメルケースまたはパスカルケースと呼ばれます」と書き分けています。Python の PEP 8 は逆に、先頭が大文字の CapWords の別名として CamelCase を挙げています。規約書で「キャメルケース」とだけ書くなら、どちらかを明記しておくと後でもめません。
スネークケース・ケバブケースとの使い分け
キャメルケースの隣では、たいてい次の書き方も使われています。同じ 3 語を変換した結果です。
| 書き方 | last update time の変換結果 | 主な使い道 |
|---|---|---|
| キャメルケース | lastUpdateTime | JavaScript・Java の変数とメソッド、多くの JSON API |
| パスカルケース | LastUpdateTime | クラスや型の名前、.NET のメソッド |
| スネークケース | last_update_time | Python・Rust の関数、データベースの列名 |
| コンスタントケース | LAST_UPDATE_TIME | 定数、環境変数 |
| ケバブケース | last-update-time | CSS のプロパティ、HTML の属性、URL |
ケバブケースは多くの言語で - が引き算になるため、識別子には使えません(MDN のケバブケースの項)。そのため CSS と JavaScript の境目で変換が起きます。CSS の background-color は、JavaScript の element.style では backgroundColor というキャメルケースのプロパティになります。CSSOM 仕様はこれを「camel-cased attribute」と呼んでいます(CSSOM)。
言語ごとの公式ルール
各言語の公式な規約が何を求めているかを、原文どおりにまとめます。
| 規約 | 変数・関数 | クラス・型 | 定数 |
|---|---|---|---|
| PEP 8(Python) | スネークケース。mixedCase は既存のコードがそうなっている場合だけ | CapWords | MAX_OVERFLOW 形式 |
| Effective Go | MixedCaps か mixedCaps。アンダースコアは使わない | MixedCaps | 同じ |
| .NET 設計ガイドライン | 公開メンバーはパスカルケース、キャメルケースは引数名だけ | パスカルケース | パスカルケース |
| Google JavaScript Style Guide | lowerCamelCase | UpperCamelCase | CONSTANT_CASE |
| Rust API Guidelines | スネークケース | UpperCamelCase | SCREAMING_SNAKE_CASE |
Go では大文字・小文字が見た目の問題にとどまりません。Effective Go は「パッケージの外から見えるかどうかは名前の最初の文字が大文字かどうかで決まる」としています。parseConfig を ParseConfig に変えれば公開 API になります。
略語の書き方は規約によって正反対
URI や ID を含む名前は、規約によって正解が逆になります。
| 規約 | ルール | 例 |
|---|---|---|
| PEP 8 | CapWords では略語の文字をすべて大文字にする | HTTPServerError のほうがよい |
| Go(Code Review Comments) | 略語は大文字か小文字にそろえる | ServeHTTP、appID(appId は不可) |
| .NET | 2 文字の略語は両方大文字、3 文字以上は先頭だけ。Id と Ok は略語扱いしない | IOStream、HtmlTag、Id |
| Google JavaScript | 略語も含めて小文字にしてから各語の先頭を大文字に | xmlHttpRequest、newCustomerId |
| Rust | 略語は 1 語として扱う | Uuid(UUID ではない) |
ブラウザの API 自体もそろっていません。MDN のキャメルケースの項は、encodeURIComponent のように略語をすべて大文字にする書き方と XmlHttpRequest のように先頭だけにする書き方を挙げ、「実際のグローバル変数 XMLHttpRequest は両方を混在させて使用しています」と指摘しています。
テキストケース変換は Google と Rust の側に立ち、略語を普通の単語として扱います。lodash や change-case と同じ動きです。
| 入力 | 変換結果 | 備考 |
|---|---|---|
encodeURIComponent | encodeUriComponent | スネークケースでは encode_uri_component |
XMLHttpRequest | XmlHttpRequest | 実際の API 名とは違う |
HTMLElement | HtmlElement | 同上 |
スネークケースの結果はどの規約でも問題ありません。パスカルケースやキャメルケースに戻した結果を Python のクラス名や Go のコードに使うときは、略語の部分を手で直してください。
API のキー名を変換する:LINE と Chatwork
日本のサービスの API でも、キーの書き方は分かれています。LINE Messaging API の Webhook は webhookEventId、replyToken、isRedelivery(deliveryContext の中)などキャメルケースです(line-openapi の webhook.yml)。一方、Chatwork API のレスポンスは room_id、avatar_image_url(自分自身の情報を取得する)、unread_room_num(自分の状態を取得する)のようにスネークケースです。
| 元のキー | 変換先 | 変換結果 |
|---|---|---|
webhookEventId(LINE) | Python の変数(スネークケース) | webhook_event_id |
isRedelivery(LINE) | 同上 | is_redelivery |
unread_room_num(Chatwork) | TypeScript の型(キャメルケース) | unreadRoomNum |
avatar_image_url(Chatwork) | 同上 | avatarImageUrl |
最後の行は Go の構造体に移すなら AvatarImageURL が規約どおりで、機械的な変換では AvatarImageUrl になります。受け取った JSON のキーを一括で変換するなら、次のように再帰で処理できます。分割のルールはツールと同じものを ASCII に絞って書いたものです。
const snake = (s) => s
.replace(/([a-z\d])([A-Z])/g, '$1_$2') // userId → user_Id
.replace(/([A-Z])([A-Z][a-z])/g, '$1_$2') // XMLHttp → XML_Http
.toLowerCase();
const toSnakeKeys = (v) =>
Array.isArray(v) ? v.map(toSnakeKeys)
: v && typeof v === 'object'
? Object.fromEntries(Object.entries(v).map(([k, x]) => [snake(k), toSnakeKeys(x)]))
: v;
const body = {
destination: 'Uxxxxxxxx',
events: [{
type: 'message',
webhookEventId: '01FZ74A0TDDPYRVKNK77XKC3ZR',
deliveryContext: { isRedelivery: false },
replyToken: 'nHuyWiB7yP5Zw52FIkcQobQuGDXCTA',
source: { type: 'user', userId: 'Uxxxxxxxx' },
}],
};
console.log(JSON.stringify(toSnakeKeys(body)));
値(replyToken の中身など)は変えず、キーだけを変えている点に注意してください。署名の検証は変換前の生のリクエストボディで行う必要があります。LINE の署名はボディ全体の HMAC-SHA256 なので、キーを変えた後の JSON で計算すると一致しません(詳しくは HMAC の解説)。
日本語環境で起きる 2 つの落とし穴
全角英字。 IME が全角モードのまま userID と入力すると、見た目は似ていても別の文字です。テキストケース変換は Unicode の大文字・小文字の区別をそのまま使うので、全角のまま単語は分けられますが、結果も全角のままです。
| 入力 | キャメルケース | スネークケース |
|---|---|---|
userID(全角) | userId | user_id |
JavaScript や Java では、全角の userID も識別子として通り、半角の userID とは別の変数になります。Python 3 は識別子を NFKC で正規化するので両者は同じ変数になりますが(Python 言語リファレンス 字句解析)、PEP 8 は標準ライブラリの識別子を ASCII に限るとしています。変換の前に NFKC で半角にそろえるのが確実です。
import re, unicodedata
def snake(name):
name = unicodedata.normalize('NFKC', name) # userID → userID
s = re.sub(r'([A-Z]+)([A-Z][a-z])', r'\1_\2', name)
return re.sub(r'([a-z\d])([A-Z])', r'\1_\2', s).lower()
for raw in ['userID', 'ユーザーID']:
print(unicodedata.normalize('NFKC', raw), snake(raw))
# userID user_id
# ユーザーID ユーザーid
カナと英字の境目。 2 行目のように、カタカナの直後の英字は単語の区切りとして扱われません。カタカナや漢字には大文字・小文字がないため、「小文字の後ろに大文字」という規則が当てはまらないからです。テキストケース変換でも同じで、ユーザーID は 1 語のまま小文字になります。空白で区切れば分かれます。
| 入力 | キャメルケース | スネークケース |
|---|---|---|
ユーザーID | ユーザーid | ユーザーid |
ユーザー ID | ユーザーId | ユーザー_id |
日本語の識別子を使うかどうかはチームの判断ですが、英語名に置き換える場合も、まず日本語の語句を空白で区切ってから変換すると結果が読みやすくなります。
数字の入った名前
数字には大文字・小文字がないので、base64Encode の 64 を前の語に含めるかどうかは変換ツールが決めるしかありません。
| 入力 | テキストケース変換・lodash 4.18.1 | change-case 5.4.4(既定) |
|---|---|---|
base64Encode | base_64_encode | base64_encode |
utf8Decode | utf_8_decode | utf8_decode |
テキストケース変換と lodash は数字を独立した語にし、change-case は既定では前の語につなげます(separateNumbers オプションで分ける)。どちらでもかまいませんが、プロジェクト内で混ぜると utf8_decode と utf_8_decode が同時に存在することになります。ライブラリは 2026-10-02 に実行した結果です。
命名をそろえるためのチェックリスト
- 「キャメルケース」がローワーかアッパーかを規約に書く。
- 略語の書き方は言語ごとの規約に合わせる。Python のクラス名と Go は全部大文字、.NET・JavaScript・Rust は先頭だけ。
- API のキーを変換するときは、変換前の生データで署名を検証してから変換する。
- 全角英字は NFKC で半角にしてから変換する。カナと英字は空白で区切る。
- 略語や数字を含む名前は、自動変換の往復(
appID→app_id→appId)で元に戻らないので、対応表を明示的に持つ。
1 つの名前を 9 種類の書き方にまとめて変換するならテキストケース変換、URL 用にアクセント記号や記号まで処理するならスラッグ変換が使えます。