30 秒概覽: 我跑翻譯狀態腳本,螢幕寫 4546,全部在
root。GitHub 上 Linux CI 是綠的。後來才看清楚兩件事。Windows 路徑的反斜線,腳本用斜線切不開。「功」的 Big5 碼後半段,本身就是 ASCII 的\。兩件事機制不同,卻常在同一台繁中 Windows 上一起出現。
我在語系 zh-TW 的 Windows 11 上維護 Taiwan.md 的翻譯狀態腳本。那天晚上照例跑 i18n-status.py,等終端機把數字印出來。主控台是 cp950。輸出沒有紅字。
螢幕停在 4546。全部在一個叫 root 的分類。Technology 是 0。
同一週推上 GitHub,Linux 上的 CI 是綠燈。
腳本變數名叫 zh_articles,掃的是 knowledge 底下除了英文、about 和底線目錄以外的路徑,日文、韓文、阿拉伯文也會被算進去。那天晚上它連分類名都切不出來,四千多條路徑被塞進同一個格子。沒有例外,沒有警告。統計看起來像整站壞掉,檔案一筆都沒少。1
磁碟上的路徑是 knowledge\Technology\某篇文章.md,資料夾之間用反斜線隔開。腳本用 split('/') 取分類名。在 Linux 上這行能用,因為路徑本來就是斜線。在 Windows 上它切不到反斜線,整條路徑原樣回來,文章被丟進預設的 root。2
改成讓 pathlib 處理目錄之後,Technology 底下是 59 篇,跟資料夾裡的東西一致。中間只隔著一個假設:你的機器用哪一種線來分開資料夾。
📝 策展人筆記: 腳本語法沒寫錯,CI 也確實跑了測試。裂開的地方在「作者實際坐的那台機器」和「工具以為你坐的那台機器」中間。這條縫不屬於任何一個環節,所以沒有人負責盯。
「功」裡面那根線
路徑是第一層。第二層老得多,埋在字裡。
Big5 在 1984 年定案,一個中文字兩個位元組。第二個位元組若落在 0x40 到 0x7E,會跟 ASCII 常用符號重疊:[、]、{、}、\、|。時任朝陽科技大學資訊管理系副教授洪朝貴(2023 年 8 月退休)在教學頁寫過:「由於 40-7E 是一般常用字元的 ASCII 碼範圍, 因此有時會給程式設計師帶來一些困擾.」3
「功」的碼是 A5 5C。後面那個 0x5C,在 ASCII 就是反斜線 \。一個逐位元組掃字串、把 \ 當跳脫或分隔符的程式,掃到「功」的後半,會以為自己遇到路徑。檔名裡有「功」,路徑裡有「功」,都可能在這裡摔一跤。
台灣跟香港的開發圈叫它「許功蓋」:「許」是 B3 5C,「功」是 A5 5C,「蓋」是 BB 5C,三個常用字連著寫像人名。4 洪朝貴另外列出「加也程陣功」,第二碼分別撞上 [、]、{、}、\,並做了掃描工具 b5tm。3 一個 bug 被取了人的名字,通常是因為它出現得夠頻繁,一代人必須有辦法指著它說話。
2015 年,部落格「黑暗執行緒」的作者換成 Visual Studio 2015。舊的 .cs 還是 BIG5 存檔。編譯器改走 Roslyn 之後,檔裡的許功蓋會變成編譯錯誤。
隔兩天同事跟他說,他們換了也卡了很久,最後爬文爬回他那篇。有網友手上成千上萬個檔,轉了一個還有一堆,「只好跟VS2015說Goodbye」。他後來寫了批次轉 UTF-8 的小工具,因為手動另存不完。5
這跟前面的 split('/') 不是同一件事。一個是現代工具假設路徑長什麼樣子。一個是四十年前選了雙位元組之後,字的身體裡住進了符號。機制不同,帳單卻常在同一台 cp950 機器上一起來。輸入那一側怎麼把字送進電腦,見 東亞文字輸入法。這裡談的是字已經在磁碟上之後,工具鏈還認不認得它。
預設值沒有為這台機器開分支
Git 預設開著 core.quotePath。位元組大於 0x80 的檔名,git status 會印成 \344\270\255 這種八進位。中文檔名還在,你只是每天看不懂自己的倉庫在說什麼。6 它跳脫的是 UTF-8 的高位元組。Big5 的 0x5C 是另一條線。看起來都是反斜線,成因不一樣。
Python 3 在 Windows 上若 open() 沒寫 encoding='utf-8',可能沿用系統語系。同一份 UTF-8 檔,Linux 讀得過,這台機器用 cp950 去解,標點或注音就壞。7 我自己付過一次:用 PowerShell 5.1 的 Get-Content | Set-Content 改 UTF-8 檔,長破折號在 diff 上變成 ??。那也是預設稅,不是第二個主題。
狀態訊息帶 emoji 時,這台 cp950 主控台會直接崩潰。字集裡沒有那些符號,Python 印不出去,例外炸到最上層。Linux CI 測不到這件事,因為它不是在這台機器上跑。
Git、Python、CI 範例路徑裡的 $HOME/project/src,沒有為 zh-TW 的 Windows 另開一條分支。
洪朝貴 2015 年接受 iThome 採訪,談政府檔案該用什麼格式打開、能活多久。報導轉述他的意思:若政府只用微軟產品開啟檔案資料,等於相信微軟的壽命會長過中華民國。8 那句話談的是檔案格式與保存年限。資料綁在哪套預設工具上,時間一拉長,就變成誰還能讀。開源協作綁的是某一種機器的預設環境。公民科技跟政府檔案格式的拉扯,見 開源社群與g0v。台灣開發者長期吸收這種落差的文化,見 台灣開源精神。
路徑分隔符、終端機編碼、CI 範例裡的 $HOME,沒有為這台機器開的支線。4546 條路徑歸錯類那天,沒有任何一行程式報錯。統計看起來正常,直到你坐在這台機器前面。
延伸閱讀
參考資料
- taiwan-md PR #1260 — 2026-07-26 合併。修復前 Windows 上 categories 只剩 root: 4546,修完 Technology zh: 59。一併拿掉會讓 cp950 主控台崩潰的 emoji。↩
- Microsoft Learn:Windows 系統上的檔案路徑格式 — .NET 文件說明傳統 DOS 路徑以反斜線作為目錄分隔符號,正斜線會被轉成反斜線。↩
- 洪朝貴:寫程式時可能遇到的 big-5 碼問題 — 教學頁列出第二碼落在 ASCII 危險區間的常用字(加也程陣功),並介紹掃描工具 b5tm。頁尾未寫職等。2015 年 iThome 稱副教授。本人首頁載 1997 至 2023 年任職朝陽資管,2023 年 8 月退休。↩2
- 維基百科:大五碼 — 載明「功」0xA55C、「許」0xB35C、「蓋」0xBB5C,並說明此問題被戲稱為許功蓋。↩
- 黑暗執行緒:潛盾機-解決 VS2015 程式檔 BIG5 相容問題 — 2015 年紀錄 Visual Studio 2015 編譯 BIG5 原始碼時,許功蓋造成編譯錯誤。文中有「只好跟VS2015說Goodbye」。↩
- git-config:core.quotePath — 官方文件說明預設會把位元組大於 0x80 的路徑顯示成八進位跳脫序列。↩
- Python 3:open() — 函式說明指出未指定 encoding 時,可能沿用系統語系作為預設編碼。↩
- iThome:洪朝貴專訪 — 2015 年專訪,文內稱朝陽科技大學資管系副教授。原頁常回 403,微軟壽命一句只採用搜尋結果可見的報導轉述,不當作逐字原話。↩