雜記 › 技術筆記 › 大小寫、駝峰、底線命名混亂?批次互轉的方法

大小寫、駝峰、底線命名混亂?批次互轉的方法

去年對接一個跑了七年的老系統,我在同一個欄位上看見四種寫法:資料庫裡是 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,前端型別不再手寫而由介面定義產生。現在回頭看,當初那兩個多小時排查的根源,不是任何一層寫錯了,而是沒有任何一處明確寫下「這個欄位在這一層應該長什麼樣」。命名風格本身沒有對錯,混著用才有代價。

📎 相關文章

PNG 壓了三遍只減 426 位元組:無損壓縮的真實邊界 2026-10-22 WebP 轉 PNG 後體積漲了幾倍:什麼時候必須轉,怎麼把漲幅壓住 2026-10-22 截圖縮到四分之一,小字糊成一團的三種原因 2026-10-22 同樣裁 300×300,頭像為什麼總偏右下角半格 2026-10-22 按每月 1.7 倍預估 18 個月,腳本和表格為什麼給出兩個數 2026-10-22