← すべての記事

Macのファイル名の濁点が分離してWindowsで見つからない時の直し方

Macから受け取ったファイルが、エクスプローラーにはちゃんと表示され、ダブルクリックすれば開ける。ところが、そのファイル名をコマンドやスクリプト、Excelのハイパーリンク、バッチ処理、アドレスバーに打ち込んだ途端、Windowsに「指定されたファイルが見つかりません」と言われる。ファイル名に濁点・半濁点付きのかな(が、ぱ、デ など)やアクセント付きの文字が含まれているなら、原因はほぼ間違いなく「Macのファイル名の濁点が分離している」状態、つまりUnicode正規化の違いです。macOSで作られたファイル名は「分解された形(NFD)」で保存されていることが多く、一方Windowsでキーボードから入力した文字は「合成された形(NFC)」になります。画面上の見た目はまったく同じでも、文字の並びとしては別物なので、Windowsは同じ名前だと認識しません。直し方は、ファイル名を合成形(NFC)に変換してリネームすることです。PowerShellの短いコマンドでやる方法と、ブラウザ上のツールでやる方法の両方をこの記事で説明します。

Macのファイル名で濁点が分離するのはなぜか(NFDとNFC)

Unicodeでは、同じ文字を2通りの方法で表せる場合があります。たとえば 「が」 は、1つの符号位置(U+304C、「合成形」=NFC)として書くこともできますし、「か」 に独立した結合用の濁点(U+304B + U+3099、「分解形」=NFD)を続けて書くこともできます。画面にはどちらも「が」と表示されます。スペルチェックもどちらも通します。人間の目には区別がつきません。

しかしファイルシステムは区別します。Windows(NTFS)はファイル名を実際の文字の並びで比較します。大文字と小文字の違いは無視しますが、が と か + ゛ を同じものとは扱いません。つまり、Macで作られた 売上データ.xlsx が実際には 売上テ + ゛ータ.xlsx として保存されていて、Windowsのキーボードで 売上データ.xlsx と入力すると、そのディスク上に存在しない名前を探していることになります。

macOSは昔から分解形を使う傾向がありました。以前のHFS+ファイルシステムはすべてのファイル名をNFDに変換して保存しており、今でも多くのMacアプリやコピー処理がNFDのファイル名を生成します。そのファイルがUSBメモリ、共有フォルダ、クラウド同期フォルダ、メール添付、Slackなどを経由してWindowsに渡ると、分解されたままの名前がそのまま付いてきます。

影響を受ける文字の例:

  • 濁点・半濁点付きのかな:がぎぐげご、ぱぴぷぺぽ、データ、プロジェクト、ゲーム
  • 韓国語のハングル:文字単位に分解され、環境によっては 한글 が ㅎㅏㄴㄱㅡㄹ のように見える
  • アクセント付きのラテン文字:café、Müller、José
  • ベトナム語:1つの母音に複数の記号が重なる

半角英数字だけのファイル名(report_final_v2.pdf)は一切影響を受けません。だからこの現象は気まぐれに見えます。「議事録.pdf」は問題ないのに「売上データ.xlsx」や「プレゼン資料.pptx」だけがおかしい、という形で現れるのはそのためです。

本当にこの問題なのかを確認する方法

リネームする前に、原因が正規化の違いであって、単なる打ち間違いや末尾のスペース、フォルダ違いではないことを確かめておきましょう。簡単な確認方法が3つあります。

1. ワイルドカードで探してみる

対象のフォルダをPowerShellで開き(フォルダの何もないところを右クリックして 「ターミナルで開く」 または 「PowerShell ウィンドウをここで開く」)、次を実行します。

Get-ChildItem 売上*.xlsx

ワイルドカードでは見つかるのに、フルネームを打つと見つからない場合、ファイル名に入力した文字とは異なる文字が含まれています。これが正規化ずれの典型的なサインです。

2. 文字数を比べる

同じフォルダで次を実行します。

Get-ChildItem | ForEach-Object { "$($_.Name.Length)  $($_.Name)" }

売上データ.xlsx という名前なら10文字のはずです。PowerShellが11と表示するなら、目に見えない余分な文字、つまり「テ」の後ろに付いた結合用の濁点が存在します。

3. PowerShellに直接聞く

Get-ChildItem | Where-Object { $_.Name -ne $_.Name.Normalize('FormC') } | Select-Object Name

これは、フォルダ内でファイル名がまだ合成形になっていないものをすべて一覧にします。問題のファイルがここに出てくれば、原因は確定です。

コマンドを打っていなくても、同じずれがWindows上で顔を出す場面があります。

  • Macの同僚が作ったExcelやWordのローカルファイルへのハイパーリンクが、自分の環境では「指定されたファイルを開くことができません」になる。
  • ファイル名の一覧を設定したバッチスクリプト、バックアップジョブ、インポートツール。
  • 「名前を付けて保存」で、上書き確認が出ずに同名の 売上データ.xlsx がもう1つ作られてしまう。
  • 一部のアプリの検索で、正確な名前では何もヒットしないのに、濁点のない部分だけで検索すると見つかる。

直し方1:WindowsのPowerShellでリネームする

コマンドラインに抵抗がなければ、必要なものはWindowsにすでに揃っています。.NETの Normalize('FormC') が分解形の名前を合成形に変換し、Rename-Item がそれを適用します。

  1. 前述の手順で、対象フォルダをPowerShellで開きます。

  2. 何が変わるかを先に確認します(この時点ではまだ何もリネームされません)。

    Get-ChildItem -Recurse -File |
      Where-Object { $_.Name -ne $_.Name.Normalize('FormC') } |
      Select-Object FullName
    
  3. 一覧に問題がなければ、リネームを実行します。

    Get-ChildItem -Recurse -File |
      Where-Object { $_.Name -ne $_.Name.Normalize('FormC') } |
      Rename-Item -NewName { $_.Name.Normalize('FormC') }
    
  4. 前のセクションの -ne を使った確認コマンドをもう一度実行します。何も表示されなければ完了です。

注意点と制限:

  • -Recurse を付けるとサブフォルダも対象になります。現在のフォルダだけでよければ外してください。フォルダ名自体が分解形になっていることもあるので、その場合は -File を外してもう一度実行します。深い階層のフォルダから先にリネームしてください。
  • これは手元のコピーをリネームする処理です。ファイルが同期フォルダ(OneDrive、Dropbox、Google Drive)にある場合、リネームはMac側にも同期されます。合成形の名前は両方の環境で問題なく使えるので、通常はそれで構いません。
  • Macからコピー&ペーストした分解形の名前を参照しているハイパーリンクやスクリプトがあれば、リネーム後はその名前が存在しなくなります。ただ、そもそもの問題は「人が入力するのは合成形」という点にあるので、実際にはあまり起こりません。

直し方2:コマンドを使わずブラウザでリネームする

PowerShellは使いたくない、あるいは複数の人から届いたファイルやZIPが雑多に溜まっている、という場合は、無料の FilenameFixer ウェブアプリ がドラッグ&ドロップで同じ変換をしてくれます。

  1. Chrome、Edge、Firefox、Safariのいずれかでウェブアプリを開きます(日本語表示に対応しています)。
  2. 問題のファイルをページにドラッグします。複数ファイルをまとめて放り込めます。
  3. ツールが分解形の名前を検出し、適用する合成形(NFC)の名前を表示します。
  4. リネームされたファイルをダウンロードして、元のファイルと差し替えます。

知っておくとよい点:

  • ファイルとファイル名はブラウザ内でローカルに処理されます。サーバーにはアップロードされないので、見積書_取引先データ.xlsx のような機密ファイルも手元から出ません。
  • Macユーザーから送られてきたZIPの中身が文字化けしている場合は、別途用意されているZIPファイル名修復ツールがアーカイブ内の名前を書き換えてくれます(200MBまで)。これでWindows側で普通に展開できます。
  • テキストを貼り付ける欄もあります。メールやスプレッドシートでファイル名の一覧をもらったのに、VLOOKUPなどの照合でディスク上のファイルと一致しないときは、一覧を貼り付けて正規化済みのテキストをコピーし直せます。

FilenameFixerがやっていることは、PowerShellでできないことではありません。どのコマンドを打つべきか知らなくて済むこと、そして上の Rename-Item の方法では扱えないZIPアーカイブに対応していること、この2点が違いです。

再発を防ぐには

リネームで直るのは今日のファイルだけです。次回以降を避けるには:

  • Mac側に、正規化を意識したZIP作成を頼むか、ウェブフォーム経由で送ってもらう。 ウェブのアップロード経路の多くは受け取り時に名前を正規化しますが、すべてではありません。
  • Macで作ったファイルをウェブアプリにアップロードするなら、Chrome拡張を使う。 FilenameFixer Chrome拡張機能 は、アップロードダイアログでファイルを選んだ時点で自動的にファイル名をNFCに変換します。社内の文書管理システムやチケット管理ツールには、最初から合成形の名前で届きます。
  • 共有するプロジェクトファイルは、できるだけ半角英数字の名前にする。 uriage_data.xlsx ならどこでも問題なく動きます。見た目は味気ないですが、スクリプトやハイパーリンク、インポート一覧から参照されるものについては、これがいちばん安全です。
  • コードの中で正規化する。 ディスクからファイル名を読み取ってユーザー入力と比較するソフトを書いているなら、比較前に両方をNFCに正規化してください。たいていの言語で1行で済みます(.NETなら .Normalize('FormC')、Pythonなら unicodedata.normalize('NFC', s)、JavaScriptなら str.normalize('NFC'))。

これはWindowsのバグでもMacのバグでもありません。どちらのOSも、渡されたバイト列をそのまま正確に保存しているだけです。同じ文字の正しい書き方が2通りあって、それが1つのディスク上で出会ってしまったからずれが生じているにすぎません。いちばん手っ取り早い決着のつけ方は、合成形に統一してリネームすることです。