杂记 › 技术笔记 › 大小写、驼峰、下划线命名混乱?批量互转的方法

大小写、驼峰、下划线命名混乱?批量互转的方法

去年对接一个跑了七年的老系统,我在同一个字段上看见了四种写法:库里是 created_time,接口文档写 CreateTime,前端类型定义里是 createTime,埋点表格里叫 Created Time。第一版代码上线后取不到值,我花了两个多小时怀疑序列化、怀疑网关、怀疑时区,最后发现是 ORM 里 mapUnderscoreToCamelCase 这个开关没打开。从那以后我把"命名风格转换"当成一件需要工具的事,而不是"顺手改一下"的事。

一、同一个词的几种长相

命名风格不是审美问题,是不同技术栈的历史约定。同一个"用户名",各处的合法写法并不相同:

风格示例主要出现在
camelCaseuserNameJavaScript / Java 变量与方法、GraphQL 字段
PascalCaseUserName类名、React 组件、C# 公共成员
snake_caseuser_namePython 变量与函数、数据库列名
CONSTANT_CASEUSER_NAME常量、环境变量
kebab-caseuser-nameURL 路径、CSS 类名、CLI 参数
Title CaseUser Name表头、按钮文案、报表列名

外部 API 也没有统一标准:GitHub 的公开接口大面积用 snake_case,Google 风格的接口用 camelCase。于是同一份数据经过三层,就要转三次。手工转的风险不在慢,在于不一致——同一批 42 个字段里,只要有一个手抖写成 userName 与 username 两种,它就跟其他字段的映射规则不同,而这类差异通常到运行期才暴露。

二、命名冲突一般在这四个地方炸

  • 数据库标识符大小写。PostgreSQL 对未加引号的标识符会折叠成小写,你按 CreateTime 建列,实际存的是 createtime,之后每次引用都得加双引号。MySQL 表名是否区分大小写取决于服务器配置与文件系统,Linux 上区分、Windows 上通常不区分,所以"我本地能跑"和"服务器报表不存在"完全可以同时成立。
  • HTTP 头。头部名称按规范是大小写不敏感的,很多运行环境读出来一律小写(Content-Type 变成 content-type),网关重写后拿不到值,多数人会先去查鉴权。
  • 签名与校验串。参与签名的字段名要和对方约定逐字符一致。把 AppKey 转成 appkey 之后验签失败,报错信息只会给你 "invalid signature",不会告诉你是大小写问题。
  • 缩写和数字。userID 还是 userId、QrCode 还是 QRCode、utf8mb4 转驼峰成 Utf8Mb4,机械转换的结果常常比原写法更难看。这类词需要一份人工白名单,而不是让规则去猜。

还有一个少有人提前防的坑:大小写转换在个别语言环境下不是可逆的字母映射。土耳其语里大写 I 转小写得到的是无点的 ı,而不是 i,Java 里 toLowerCase() 不带 Locale.ROOT 就会踩到,字段名在测试环境好好的,部署到设置了区域设置的机器上就匹配不上。

三、我现在的批量转换做法

  1. 先把分隔符统一。字段名里可能混着空格、下划线、连字符,我习惯先用批量查找替换加一条正则规则,把 [_\-\s]+ 全替成单个下划线,让后续转换有稳定的输入。
  2. 整列粘进大小写转换,分别取全大写、全小写、首字母大写和驼峰、下划线、连字符几种输出。42 行一次处理完,三份目标命名各取一列,比在编辑器里逐个改省掉的不只是时间,还有出错率。
  3. 结果先过一遍正则校验再落文档。用正则表达式测试匹配 ^[a-z][a-z0-9]*(_[a-z0-9]+)*$ 这类模式,凡是列出不合格行的,就是转换没能识别分词的字段(多半是缩写或粘连的数字),单独人工处理。
  4. 把规则固化到检查里,而不是靠约定。前端加 ESLint 的 camelcase 规则,Python 侧用 linter 的命名检查,数据库列名在 migration 评审清单里写死 snake_case。转换工具解决存量,lint 解决增量。
  5. 改名要往下游同步:视图、BI 报表、导出的模板、给运营用的对照表,都按新名字重新生成一次。老系统里最容易漏的是别人手工维护的 Excel 取数模板。

四、几个边界

大小写和命名风格只作用于英文字母。中文、全角字母、代码里的中文注释不参与转换,也不会被破坏,但混排文本整批处理时注释会跟着变格式,所以我一般只贴字段清单,不贴整段源码。

不要为了"统一"把整份源文件全转成大写或小写。代码的可读性和 diff 噪音都是代价,正确范围是标识符、表头、常量名这一层级,正文文案另按 Sentence case 处理。

对外契约改名要留过渡期。字段级别的重命名对调用方是破坏性变更,常见做法是新名字与旧名字并行输出一个版本周期,文档里注明废弃时间。

五、常见疑问

Q:camelCase 和 PascalCase 到底怎么选?

看它是不是"类型"。类、组件、接口名用 PascalCase,实例、变量、方法、函数参数用 camelCase,这是 Java、JavaScript、C# 社区共同的约定。

Q:数据库字段该用什么命名?

snake_case 更稳:跨库可移植、不依赖引号包裹、在 SQL 里可读性最好。定下来之后,让 ORM 的自动转换去负责映射到代码里的 camelCase,而不是两边手工对齐。

Q:为什么我本地正常的代码,发到服务器上就报字段不存在?

大概率是大小写敏感性不同。Windows 文件系统不区分、Linux 区分,数据库表名和列名的行为跟着配置与平台走。把标识符统一成小写加下划线,可以从根上避免这类"平台依赖"。

Q:几十行表头能一次转完吗?

可以,多行整批处理正是这类工具存在的理由。要点是先统一分隔符,再选目标风格,最后用一条正则校验输出,三步都不能省。

Q:转换会不会影响已经加密或参与签名的字符串?

会改变参与计算的原文,结果就完全不同。签名、哈希、Base64 这类字符串永远保持原样,只转换人写的标识符,两者不要放在同一次批量里。

那个老系统后来我做了一次全量重命名:库里全部 snake_case,接口出参统一 camelCase,前端类型不再手写而由接口定义生成。现在回头看,当初那两个多小时排查的根源,不是任何一层写错了,而是没有任何一处明确写下"这个字段在这一层应该长什么样"。命名风格本身没有对错,混着用才有代价。

📎 相关文章

这个IP是哪里的?归属地和运营商怎么查、能查到什么 2026-10-15 压缩成一行的JS看不懂?在线美化、格式化代码 2026-10-15 \u4e2d是什么鬼?中文与Unicode编码在线互转 2026-10-15 二进制、十六进制总是算不对?2/8/10/16进制互转方法 2026-10-15 接口返回的JSON怎么变成表格?在线转Excel/CSV一步到位 2026-10-15