大小写转换器

在不同文本大小写样式之间转换

大写
-
小写
-
标题大小写
-
句子大小写
-
驼峰式
-
帕斯卡式
-
蛇形式
-
短横线式
-
常量式
-

Unicode 大小写映射不是简单的 A↔Z 互换

ASCII 让所有人以为大小写是一个完美的双向映射:A–Z 与 a–z 一一对应,大写化和小写化看起来是可逆的。Unicode 有意打破了这个模型。标准中的 SpecialCasing.txt 定义了一对多、依赖 locale、依赖上下文的映射,而 JavaScript 的 toUpperCase() 和 toLowerCase() 忠实地实现了它们 — 所以这些意外会直接落在生产代码里。 德语 ß 是经典的一对多案例:'ß'.toUpperCase() 返回 'SS',输出比输入更长。大写的 ẞ(U+1E9E)在 2008 年加入 Unicode,并且自 2017 年起被德语正字法正式承认,但默认映射仍然输出 SS。这意味着 'straße'.toUpperCase().toLowerCase() 会变成 'strasse' — 往返转换摧毁了原始拼写。 土耳其语和阿塞拜疆语区分带点的 i 和不带点的 ı。在土耳其语 locale 下,'i'.toLocaleUpperCase('tr') 得到 'İ'(U+0130),'I'.toLocaleLowerCase('tr') 得到 'ı'(U+0131)。而在默认 locale 下,'İ'.toLowerCase() 返回 'i' 加上一个组合用上点(U+0307),因此 .length 是 2。这就是著名的 Turkish-I 缺陷家族:任何对配置键或协议 token 做小写化的软件,一旦跑在默认 locale 为土耳其语的机器上就会出错。 希腊语则引入了上下文敏感性:大写 Σ 在词中小写为 σ,在词尾小写为 ς(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。可靠的分词器改用两条规则:在小写到大写的转换处开新词;在连续大写串中,在后面紧跟小写字母的最后一个大写字母处开新词 — 于是得到 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 等约四十个),所以地道的 Go 写 userID 和 ServeHTTP。同一个短语在不同生态里的'正确' camelCase 因此并不相同;转换器只能选定一种策略并一以贯之。

大小写转换是有损的:往返转换回不到原点

在命名约定之间转换会破坏信息,值得弄清楚到底丢掉了什么。多数转换器先把输入归一化为规范单词列表(canonical word list)— 全小写的单词序列,分隔符丢弃 — 再按目标风格重新拼接。凡是产生相同单词列表的两个输入,从此永远无法区分。 第一个牺牲品是单词内部的大写。HTML_parser 转成 camelCase 是 htmlParser;转回去得到 html_parser — 没有任何地方记录 HTML 原本是全大写。第二个是数字边界:user_id_2 变成 userId2,逆转换输出 user_id2,因为数字不携带大小写信息,无法标记分隔符曾在哪里。第三个是前导分隔符:Python 中表示内部成员的惯例 _private 转成 camelCase 后就是 private — 承载语义的前缀直接消失,触发 Python name mangling 的双下划线也一样。连续分隔符(a__b)会塌缩成一个。 工程结论:永远不要重新推导名字。跨层映射标识符的代码生成器 — 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" 表,以后每条查询都必须永远带引号;把这套 schema 迁到 Oracle,折叠方向又会翻转。 最后一个陷阱是文件系统。macOS 的 APFS 和 Windows 的 NTFS 默认不区分大小写(但保留大小写),Linux 的 ext4 区分。解析到 button.tsx 的 import './Button' 在每台开发笔记本上都能跑,只在 Linux CI 上失败 — 这是 "works on my machine" 最稳定的来源之一。

跨命名约定的重构:一套实用工作流

重命名一个领域概念,意味着同时追踪它的所有命名变体:TypeScript 里的 userAccount、SQL 和 Python 里的 user_account、CSS 类名和 URL 里的 user-account、环境变量里的 USER_ACCOUNT、类名里的 UserAccount。只搜其中一种变体,就只能找到一部分用法。可靠的工作流是:先生成全部变体(本工具粘贴一次即可),再用 alternation 一次性搜索 — ripgrep 一趟就能扫完 — 并在做任何替换之前逐一审查命中结果。 替换本身可以靠 IDE 支持变得安全:JetBrains 的 "Preserve case" 替换选项和 VS Code 的 preserve-case 开关(替换框里的 AB 按钮)能在一次操作中同时把 userAccount 映射为 memberProfile、把 UserAccount 映射为 MemberProfile,不必做五次独立替换。 在 API 边界上,干脆不要手工转换。线上格式通常是 snake_case(Stripe、多数 Python 和 Ruby 后端),而 JS 客户端期望 camelCase;应在序列化层用声明式策略只转换一次 — Rust 用 serde 的 rename_all = "camelCase",Java 用 Jackson 的 PropertyNamingStrategies.SNAKE_CASE,Node 用 camelcase-keys。有一个警告:深层键转换必须跳过那些键是数据而非标识符的 map — 对以外部 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.