少し前にMacデビューしました!

問題発生

Macで以下のような作業をしました。

  1. GCS(Google Cloud Storage)からファイルをPC(Mac)にダウンロード
  2. そのファイルをGCSに再アップロード
  3. GCSアップロードをトリガーに、ファイル名をBigQueryに保存

BigQueryで保存したはずのファイル名を検索すると、なぜか「見つからない」 という問題が発生しました。

調べてみると、実はMacの「ある仕様」が原因でした。

原因となる仕様

一言でいうと、Macだけ日本語の「濁点(゛)」や「半濁点(゜)」の扱い方が違うからです。

  • 一般的なシステム (Windows, Linux, Webなど) の記録方法 (NFC形式)
    • 「ど」という文字を、そのまま「ど」という1文字として記録します。
  • Macの内部的な記録方法 (NFD形式)
    • Macはファイル名を保存するとき、「ど」という文字を「と」と「゛(濁点)」という2つのパーツに分解して記録しています。
    • Finder上ではちゃんと「ど」と表示されるため、ユーザーはこの分解に気づきません。
見た目 一般的なシステム(NFC) Macの内部(NFD)
「ど」 (1文字) 「と」+「゛」 (2パーツ)
「ぱ」 (1文字) 「は」+「゜」 (2パーツ)
「ジ」 (1文字) 「シ」+「゛」 (2パーツ)

 

↑ MacのFinderで見たところ

ダミー.png」 に見えるけれど、実は「タ゛ミー.png」に変換されている。

 

Macと他のシステムが同じ文字を違う方法で記録しているため、「見た目は同じなのに、コンピュータにとっては別物」という状況が生まれます。
この問題は、Macが歴史的に採用しているNFDという文字コードの記録方式が、一般的なNFC方式と異なるために発生します。これは濁音・半濁音を持つ日本語ファイル名で特に顕著になります。

これが「見えない文字化け」の正体です。

今回のケースで何が起きていたか

① GCS上のファイル名
“ダミー.png”(NFC 正常な状態)

↓ Macにダウンロード

② Macのファイルシステム上
“ダミー.png”(NFD 見た目は同じ・内部で分解される)

↓ MacからGCSに再アップロード

③ GCS上のファイル名(NFD 再アップロード後)
“ダミー.png”(分解されたまま保存)

↓ BigQueryに保存

④ BigQueryのファイル名
“ダミー.png”(NFD 分解されたまま)

①と④は見た目は同じでも別物として扱われるため、検索で一致しませんでした。

どうしたらいいか

ユーザー側では防げない

これはMacのファイルシステムの仕様なので、ユーザーがどんなに気をつけても防げません。

システム側の対策が必要

ファイル名を受け取るプログラムで、受け取った直後に「分解された文字をまとめ直す」処理を1行追加するだけで解決できます。

import unicodedata

# Macから受け取ったファイル名(分解された状態)
filename = "ダミー.png"

# NFCに直す
filename = unicodedata.normalize('NFC', filename)

たった1行で、クロスプラットフォームの文字コード問題を未然に防げます。

まとめ

自分だけ気をつけていても、誰かのMacを経由していたら、知らないうちにファイルがサイレント文字化けしているかもしれません・・。

Mac + 日本語ファイル名は避けるのが安全。