😵

Google Cloud Storage(GCS)で日本語ファイルが見つからない!MacとGCSのUnicode正規化の罠

2024/06/10に公開

はじめに

Google Cloud Storage (GCS) を利用していると、Macからアップロードした日本語名を含むファイルが見つからないという問題に直面することがあります。

具体的には、Macで「がんばるぞ.pdf」というファイルを作成し、それをGCSにアップロード後に、Vertex AI SearchでndjsonファイルでURIを指定して、ファイルをデータソースとしてインポートを実行しました。
しかし、「OBJECT_NOT_FOUND」というエラーが発生して、インポートに失敗する事象が発生しました。

{"id":"1","content":{"mimeType":"application/pdf","uri":"gs://test/がんばるぞ.pdf"}}

この問題は、システム間のUnicode正規化の違いが原因で発生します。

Unicode正規化とは?

Unicode正規化は、文字列の比較や検索を正確に行うために、異なる表記の文字を統一された形式に変換するプロセスです。
同じ意味を持つ文字が異なる表現方法で記述されている場合、それらを一貫した形式に変換することで、文字列の一致判定やデータ処理を容易にします。

異なる表記の文字が同じ意味を持つ場合、それらを統一された形式に変換しないと、比較や検索が正確に行えません。例えば、「が」という文字は、単一の文字「が」としても、「か」と濁点「゛」を組み合わせたもの「か゛」としても表現できます。これらを同じものとして扱うために、Unicode正規化が使われます。

Unicode正規化の形式: NFCとNFD

Unicode正規化には4つの主要な正規化形式がありますが、ここでは最も一般的な2つの形式を紹介します。

  1. NFC (Normalization Form C, Canonical Composition):
    • 可能な限り文字を合成する形式です。例えば、「か」と濁点「゛」を組み合わせて「が」に変換します。
  2. NFD (Normalization Form D, Canonical Decomposition):
    • 可能な限り文字を分解する形式です。例えば、「が」を「か」と濁点「゛」に分解します。
文字 正規化形式 表示例 Unicode
NFC U+304C
NFD か + ゙ U+304B (か) + U+3099 (゛)

MacとGCSのUnicode正規化の違い

Macのファイルシステムは通常NFDを使用しており、GCSはNFCを使用しています。
これにより同じ文字でもコードポイントが異なるため同一と判定がされない問題が発生します。

解決策

一番の解決策はファイル名に半角英数のみを使い日本語を使わないことですが、今回はそれ以外の方法で解決策を考えます。

ndjsonの本文をNFD形式に変換する

例えば、JavaScriptであればString.protype.normalize()メソッドでUnicode正規化を指定して文字列を変換することができます。
ファイルへの書き込み時にNFD形式で書き込みをすることで、NFD形式でURIを参照することができます。

fs.writeFileSync("test.ndjson", content.normalize("NFD"))

しかし、注意点としてWindowsなどのOSでファイルアップロードした場合はファイル名がNFC形式となるため、問題が発生します。
そのため、複数のOS環境を考慮する場合は、条件分岐を入れる対策が必要になります。

アップロード時にファイル名をNFC形式に変換する

ファイルのアップロードをプログラムやCUIツールで実施する場合は、アップロード時にのみファイル名をNFC形式に変換するのが一番良い選択肢です。
この方式であれば、OSの違いを意識する必要がなくなります。

NFC形式のファイル名で保存する

ファイル保存時にファイル名をNFC形式で保存することも考えられます。
しかし、NFD形式のファイルシステム上でNFC形式のファイル名を取り扱うことになるので、個人的にはオススメはしません。

まとめ

MacとGCS間のUnicode正規化問題は、ファイル名の正規化を適切に処理することで解決できます。各解決策にはメリットとデメリットがありますので、ニーズに最も適した方法を選択してください。

Discussion