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、およびアンダーラインディレクトリ以外のパスをスキャンします。日本語や韓国語、アラビア語もカウントされていました。その夜、それは分類名さえ区切ることができず、4000件以上のパスが同じセルに詰め込まれてしまいました。例外もなく、警告もありませんでした。統計上はサイト全体が壊れたように見えましたが、ファイルは一つも減っていませんでした1。
ドライブ上のパスはknowledge\Technology\某篇文章.mdであり、ディレクトリ間はバックスラッシュで区切られています。スクリプトはsplit('/')を使って分類名を取得します。Linux上ではこの行は機能しますが、なぜならパス自体がスラッシュだからです。Windows上ではバックスラッシュを区切れないため、パス全体がそのまま戻ってきてしまい、記事はデフォルトのrootに投入されてしまいました2。
pathlibを使ってディレクトリ処理するように変更した後、Technologyの下には59件があり、これはフォルダ内の内容と一致しました。中間にあるのは一つの仮定だけです。それは「あなたのマシンがどの線でディレクトリを区切っているか」という点です。
同じパスに対して、二通りの分割方法。split('/')はスラッシュを見つけられず全体をそのまま返し、PureWindowsPathはバックスラッシュを認識しTechnologyを返します。Taiwan.mdの貢献者によって作成され、CC BY-SA 4.0です。
📝 キュレーターノート: スクリプトの構文に誤りはありませんし、CIも確かにテストを実行しました。亀裂が入ったのは、「作者が実際に座っているマシン」と「ツールがあなたが座っていると想定しているマシン」の間です。この隙間はどのプロセスにも属していないため、誰も監視していません。
「功」の中の線
パスは第一層です。第二層は遥か昔のもので、文字の中に埋め込まれています。
Big5は1984年に確定し、一つの漢字が二バイトを占めます。第二バイトが0x40から0x7Eの範囲にある場合、ASCIIの一般的な記号と重複します。具体的には[、]、{、}、\、|です。当時の朝陽科技大学情報管理学科の副教授であった洪朝貴(2023年8月退職)は、自身の講義ページに「40-7Eは一般的な常用文字のASCIIコード範囲であるため、時としてプログラマーにいくらかの困惑をもたらすことがあります」と記述しています3。
「功」のコードはA5 5Cです。後者の0x5Cは、ASCIIではバックスラッシュ\そのものです。バイト列を一つずつスキャンし、\をエスケープ文字または区切り文字として扱うプログラムは、「功」の後半部分をスキャンした際に、パスに遭遇したと誤認することがあります。ファイル名に「功」が含まれていたり、パスに「功」が含まれていたりする場合、ここでつまずく可能性があります。
台湾と香港の開発コミュニティではこれを「許功蓋(hsiu-kong-gai)」と呼んでいます。「許」はB3 5C、「功」はA5 5C、「蓋」はBB 5Cという三つの常用漢字を連続して書いたものが人名として使われる例です4。洪朝貴氏はさらに「加也程陣功」を列挙し、第二バイトがそれぞれ[、]、{、}と衝突するケースを示し、スキャンツールb5tmを作成しました3。あるバグが人の名前に冠されたのは、それが十分に頻繁に発生し、世代間で指さして話せる必要があったためです。
2015年、ブログ「黑暗執行緒(Dark Thread)」の著者がVisual Studio 2015に切り替えた際、古い.csファイルはまだBIG5で保存されていました。コンパイラがRoslynに移行した後、ファイル内の許功蓋はコンパイルエラーを引き起こしました。
数日後、同僚から「彼らも切り替えましたが、長く詰まっており、最終的に彼の記事を遡って修正した」と聞きました。あるネットユーザーは何千ものファイルを抱えていましたが、変換してもまだ残っているため、「VS2015にさよならするしかなかった」とのことです5。
これは先ほどのsplit('/')とは別の問題です。前者は現代のツールがパスをどのように想定しているかという話であり、後者は40年前に二バイト文字を選択した結果、文字の内部に記号が住み着いてしまったという話です。メカニズムは異なりますが、請求書(この場合はエラー)は同じcp950マシン上で同時に届くことがよくあります。入力側ではどのように文字をコンピュータに送り込むかについては、東亞文字輸入法を参照してください。ここでは、ファイルがすでにディスク上にある後で、ツールチェーンがそれを認識するかどうかについて論じています。
デフォルト値は本マシン用にブランチを切っていない
Gitはcore.quotePathをデフォルトで有効にしています。バイト数が0x80を超えるファイル名は、git statusによって\344\270\255のような八進数エスケープとして表示されます。中国語のファイル名自体は存在しますが、あなたはただ毎日自分のリポジトリが何を言っているのか理解できないだけです6。これはUTF-8の高位バイトをエスケープしているものです。Big5の0x5Cは別の話です。見た目はどちらもバックスラッシュですが、原因が異なります。
同じファイルに対して、デフォルト値の下には\345\212\237という連なりがあります。ここでのバックスラッシュはGitが付加したエスケープであり、「功」の中の0x5Cとは無関係です。Taiwan.mdの貢献者によって作成され、CC BY-SA 4.0です。
Python 3がWindows上でopen()を呼び出す際にencoding='utf-8'を指定しなかった場合、システムロケールを引き継ぐ可能性があります。同じUTF-8ファイルでも、Linuxでは正しく読み込めますが、このマシンでcp950を使ってデコードしようとすると、句読点や注音(ピンイン)が壊れます7。私自身も一度経験しました。PowerShell 5.1のGet-Content | Set-Contentを使ってUTF-8ファイルに変換した際、長いダッシュ記号がdiffで??になってしまったのです。これもデフォルト税の一種であり、第二のテーマではありませんでした。
ステータスメッセージに絵文字を伴わせた場合、このcp950コンソールは直接クラッシュします。そのコードセットにはそれらの記号が含まれていないため、Pythonは出力できません。例外が最上位で爆発します。Linux CIではこのことはテストされません。なぜならそれはこのマシン上で実行されていないからです。
Git、Python、CIの例にある$HOME/project/srcのようなパスは、zh-TW版Windowsのために別のブランチを切ったわけではありませんでした。
洪朝貴氏は2015年にiThomeのインタビューを受け、政府ファイルを開く際にどの形式を使うべきか、どれくらいの期間生存できるかについて語っています。記事は彼の意図を次のように伝えています。「もし政府がMicrosoft製品だけでファイルを操作する場合、それはMicrosoftの寿命が中華民国よりも長いと信じているに等しい」と8。この発言はファイル形式とその保存期間に関するものです。データがどのデフォルトツールセットに縛られているかによって、時間が経つにつれて誰が読み取れるかが決まります。オープンソースの協働は特定のマシンのデフォルト環境に結びついています。市民テクノロジーと政府ファイル形式との間の綱引きについては、開源社群とg0vを参照してください。台湾の開発者が長期的に吸収してきたこのギャップという文化については、台湾オープンソース精神を参照してください。
パス区切り文字、ターミナルのエンコーディング、CIの例にある$HOMEは、本マシン用に枝分かれしたわけではありませんでした。4546件のパスが誤ったカテゴリに分類された日には、どの行もエラーを報告しませんでした。統計上は正常に見えましたが、あなたがこのマシンの前に座っているときだけです。
関連資料
- 台湾オープンソース精神:台湾の開発者がオープンソースに関わる文化と文脈について。
- 東亞文字輸入法:文字がどのようにキーボードから入力されるのか、コード表から鍵盤に至るまで。
- 開源社群とg0v:オープンデータと政府形式との協働について。
画像の出典
- 「功」のBig5コードとバックスラッシュ(hero):Taiwan.mdの貢献者による図解であり、CC BY-SA 4.0です。
public/article-images/technology/big5-gong-5c-backslash.webpに保存されています。下段の行はPython 3が実際に'許功蓋'.encode('big5')を実行した出力であり、コードポイントはWikipediaの大五碼項目と一致します4。 - split('/') と PureWindowsPath:Taiwan.mdの貢献者による図解であり、CC BY-SA 4.0です。
public/article-images/technology/windows-path-split-vs-pathlib.svgに保存されています。内容はPython 3の実際の実行結果を示しており、PureWindowsPathはどのOS上でもWindowsの規則に従ってパスを分割するため、Windowsマシンがなくても再現可能です。 - Git core.quotePath の八進数出力:Taiwan.mdの貢献者による図解であり、CC BY-SA 4.0です。
public/article-images/technology/git-quotepath-octal-cjk.svgに保存されています。内容はリポジトリに本文ファイル名を追加した際のgit status --shortの実際の出力であり、この動作はOSとは無関係です。
参考文献
- taiwan-md PR #1260 — 2026年7月26日マージ。修正前、Windows上のcategoriesはrootのみで4546件でしたが、修正後はTechnology zh: 59件となりました。cp950コンソールをクラッシュさせる絵文字も削除されました。↩
- Microsoft Learn:Windows システム上のファイルパス形式 — .NETドキュメントでは、従来のDOSパスがバックスラッシュをディレクトリ区切り文字として使用し、正斜線はバックスラッシュに変換されると説明されています。↩
- 洪朝貴氏:プログラミングで遭遇するBig5コードの問題 — 講義ページでは、第二バイトがASCIIの危険域に入る常用漢字(加也程陣功)を列挙し、スキャンツールb5tmを紹介しています。末尾には職位の記載はありません。2015年iThomeでは副教授と紹介されています。筆者は1997年から2023年まで朝陽資管で勤務し、2023年8月に退職しました。↩2
- Wikipedia:Big5 — 「功」を0xA55C、「許」を0xB35C、「蓋」を0xBB5Cとして記載し、この問題が「許功蓋」と呼ばれていることを説明しています。↩2
- 黑暗執行緒:潜盾機-VS2015プログラミングファイルのBIG5互換性問題解決 — 2015年の記録で、Visual Studio 2015がBIG5のソースコードをコンパイルする際に許功蓋がコンパイルエラーを引き起こしたことが記されています。記事には「VS2015にさよならせざるを得なかった」という記述があります。↩
- git-config:core.quotePath — 公式ドキュメントでは、バイト数が0x80を超えるパスは八進数エスケープとして表示されると説明されています。↩
- Python 3:open() — 関数説明では、エンコーディングを指定しない場合、システムロケールがデフォルトのエンコーディングとして使用される可能性があると指摘されています。↩
- iThome:洪朝貴氏インタビュー — 2015年のインタビューで、筆者は朝陽科技大学情報管理学科の副教授と紹介されています。元のページは頻繁に403エラーを返したため、Microsoftの寿命に関する発言は検索結果から確認できる記事の内容を引用したものであり、逐語訳ではありません。↩