Web便利ツール集

Macのファイル名がWindowsで濁点が分離する原因と直し方|NFD・NFCの違い

文字化け濁点Unicode正規化Macファイル名

Macで作ったファイルをWindowsに渡したら、「資料.pdf」の「が」が「か」と「゛」に分かれて表示された。検索しても見つからない、システムにアップロードするとエラーになる——そんな状況の記事です。

結論から言うと、原因は壊れたデータではなく、同じ文字が別の並べ方で保存されているだけです。ファイル名を「合成形式(NFC)」にそろえれば直ります。この記事では、症状の見分け方、Windowsでの一括変換、そして変換するときに起きやすい落とし穴を整理します。

結論:濁点の分離は「NFD」と「NFC」の違い

日本語の「が」は、Unicode上で2通りの表し方があります。

形式呼び方「が」の中身
NFC(合成済み)1文字で表すU+304C(が)の1文字
NFD(分解)基底文字+濁点で表すU+304B(か)+U+3099(結合用濁点)の2文字

画面では同じ「が」に見えても、コンピューターにとっては別の文字列です。Macの環境では、ファイル名がNFD(濁点が分解された形)で扱われる場面があり、それをWindowsに持っていくと「か゛」のように分かれて見えることがあります。

同じ見た目でも、NFDとNFCは別の文字列として比較されます。これがこの問題のすべての原因です。

なお、Mac側の保存の仕組み(どのファイルシステムでどう正規化されるか)は、OSやファイルシステムのバージョンによって異なるとされています。本記事は公式仕様の解説ではなく、症状の見分け方と対処に絞った実務メモです。Appleやマイクロソフトの公式情報が必要な場合は、各社の資料を確認してください。

影響を受ける文字

分解されるのは、主に濁点・半濁点が付く文字です。

  • が行・ざ行・だ行・ば行(濁点)
  • ぱ行(半濁点)
  • カタカナの濁音・半濁音(ガ、パ、ヴなど)
  • 欧文のアクセント付き文字(é など)

一方、漢字・ひらがなの清音・長音「ー」は、変換しても1文字のままです。つまり「資料」「報告書」のようなファイル名は症状が出ず、「がっこう」「パンフレット」のように濁点を含む名前だけがおかしくなるため、「たまに起きる不具合」に見えがちです。

症状から原因を切り分ける

「濁点が分離する」という症状と、「ファイル名が完全に文字化けする」症状は、別の問題です。最初に切り分けます。

見え方考えられる原因対処の方向
「か゛」と、濁点だけ浮いて見える正規化形式の違い(NFD)NFCへ変換(本記事)
意味の読めない文字や記号の羅列になる文字コードの解釈違い(ZIPなど)解凍ソフトや解凍時の文字コード指定を見直す
検索しても見つからないが、見た目は同じNFDとNFCの不一致の可能性次の手順で確認

ZIPで完全に化ける場合は、WSL2の unzip -Ocp932 で回避できたという報告もあります(個人の検証例で、環境によって結果は異なると考えられます)。PDFの添付ファイル名や本文が化ける場合は、PDFが文字化けする原因と直し方も確認してください。

見た目では判断できない:ツールで確認する方法

NFDかNFCかは、目視ではほぼ判断できません。フォントによっては、NFDの「が」が合成形と見分けがつかないほど綺麗に表示されます。次の3つの方法なら、ブラウザだけで確かめられます。

1. 文字数を数える

文字数カウントツールにファイル名を貼り付けます。このツールは文字数をコードポイント単位で数え、UTF-8のバイト数も表示します。

筆者が がぎぐパ資料ファイル.txt(見た目は14文字)をNFCとNFDで実測した結果は次のとおりです。

形式文字数(コードポイント)UTF-8バイト数
NFC1434
NFD1846

見た目が同じなのに、文字数が4文字、バイト数が12バイト多いなら、濁点が分解されています。濁点・半濁点の数だけ、文字数は1ずつ、バイト数は3ずつ増える計算です(上の例では濁点系が4文字)。

2. 差分を取る

テキスト差分比較ツールの左右に、「Macから来たファイル名」と「Windowsで打ち直したファイル名」を貼り付けます。見た目が同じでも、行が「変更あり」と判定されたら、中身が違います。このツールは行を完全一致で比較するため、NFDとNFCの違いも差として出ます。

3. URLエンコードして見る

URLエンコードツールに通すと、バイト列の違いがはっきり出ます。「が」で実測すると次のようになりました。

形式encodeURIComponent の結果
NFC%E3%81%8C
NFD%E3%81%8B%E3%82%99

NFDの結果の後半 %E3%82%99 が結合用濁点(U+3099)です。ファイル名をURLに含めたとき、%E3%82%99 が混ざっていたらNFDの目印になります。URLまわりの文字化けは、URLエンコードで文字化けが直らない原因も参考になります。

Windowsでファイル名をNFCに直す方法

見た目や文字数で原因を確かめたら、ファイル名をNFCに変換します。

方法1:PowerShellで一括変換する

次のコマンドは、指定フォルダ直下のファイルのうち、NFCになっていないものだけを変換します。実際にWindows(PowerShell 5.1)で、NFDのファイル名を作って試した手順です。

# 対象フォルダを指定(例)
$dir = "C:\work\from-mac"

Get-ChildItem -LiteralPath $dir |
  Where-Object { -not $_.Name.IsNormalized([Text.NormalizationForm]::FormC) } |
  ForEach-Object {
    Rename-Item -LiteralPath $_.FullName `
      -NewName $_.Name.Normalize([Text.NormalizationForm]::FormC)
  }

実測では、NFDの「資料がめ.txt」と「パ.txt」が、変換後にそれぞれ8文字・5文字のNFCの名前になりました。サブフォルダまで処理したい場合は Get-ChildItem に -Recurse を付けますが、先にコピーを取ってから実行してください(理由は次の「落とし穴」で説明します)。

方法2:Node.jsで変換する

Node.jsが入っている環境なら、次のスクリプトでも同じ処理ができます。同名のファイルがすでにある場合は、上書きせずにスキップする作りにしています。

// nfc-rename.mjs  使い方: node nfc-rename.mjs <フォルダ>
import { readdirSync, renameSync, existsSync } from "node:fs";
import { join } from "node:path";

const dir = process.argv[2];
for (const name of readdirSync(dir)) {
  const nfc = name.normalize("NFC");
  if (nfc === name) continue;
  if (existsSync(join(dir, nfc))) {
    console.log(`SKIP (same name exists): ${JSON.stringify(name)}`);
    continue;
  }
  renameSync(join(dir, name), join(dir, nfc));
  console.log(`OK: ${name.length} -> ${nfc.length} chars`);
}

このスクリプトの動作確認はWindowsで行っています。Mac上で実行したときの挙動(Macのファイルシステムが正規化の違いをどう扱うか)は検証していないため、Mac側で使う場合は、必ずコピーしたフォルダで試してください。

方法3:専用ソフトを使う

NFDからNFCへの変換に対応したファイル名変換ソフトもあります(例として、BandiNamerが紹介されています)。コマンド操作に抵抗がある場合の選択肢ですが、提供状況や対応OSは公式ページで確認してください。

他所ではあまり書かれていない落とし穴

変換方法はよく紹介されていますが、実務で困るのは変換したあとや、変換する前の判断です。

落とし穴1:同じ名前のNFDとNFCが同じフォルダに共存する

WindowsのNTFSでは、見た目が同じNFDとNFCの2つのファイルが同じフォルダに併存できます。実測でも、ガ.txt(NFD)と ガ.txt(NFC)を同じフォルダに作成でき、フォルダの中身は2件として数えられました。

そのため、すでにNFCの同名ファイルがある状態でNFDのファイルをNFCにリネームすると、衝突します。PowerShellでは次のようなエラーになりました。

Cannot create a file when that file already exists.

上書きされない点は安全ですが、一括変換が途中で止まったり、「同じ名前のファイルが2つあるように見える」状態が残ったりします。Macから受け取ったフォルダに、以前自分で保存した同名ファイルが混ざっていないかを、変換前に確認してください。

落とし穴2:ファイル名が長く(バイト数が多く)なる

NFDは濁点を別の文字として持つため、NFCより文字数もバイト数も増えます。先ほどの実測では、34バイトが46バイトになりました(約1.35倍)。

ファイル名や保存先の長さに上限があるシステム(アップロード先、バックアップソフト、共有サーバーなど)では、NFCなら通る名前がNFDだと上限を超えることが考えられます。「文字数は上限以内なのにエラーになる」場合は、バイト数と濁点の数を疑ってください。どのシステムでどの上限が適用されるかは環境ごとに異なるため、実際の仕様は各システムの資料で確認が必要です。

落とし穴3:変換するとリンクや参照が切れる

ファイル名をNFCに変えると、そのファイル名を参照していたものが対象を見失います。たとえば次のようなものです。

  • Excelやドキュメント内のファイルへのリンク
  • HTMLやMarkdownから参照している画像のパス
  • バッチ処理・スクリプトに書き込んだファイル名
  • 共有サーバー上の既存URL

Webサイトの画像などで、リンク先のファイル名がNFD、リンク元の記述がNFCだと、サーバーによっては「ファイルが見つからない」になります(URLでは %E3%82%99 を含むかどうかで別のパスとして扱われるため)。ファイル名を直したら、参照側も同じ形式にそろえるのが原則です。Web公開用のファイルは、そもそも日本語名を避けて半角英数字にしておくと、この問題自体を避けられます。

落とし穴4:コピペで再びNFDが混ざる

直したつもりでも、Mac上のファイル名を文字として取り出して貼り付けると、NFDがそのまま入ることがあります。たとえば、Finderのファイル名をコピーして、フォームや表計算ソフトの検索欄に貼り付ける場合です。

見た目は同じなのに、検索でヒットしない、VLOOKUP で一致しないといった症状になります。この場合も、先ほどの文字数カウントと差分比較で原因を確認できます。文字列として貼り付けてしまった値は、文字列としてNFCに変換するか、半角英数字で打ち直すのが確実です。

なお、全角・半角が混在して照合できない場合は別の問題で、半角カナの濁点が2文字として数えられる点を含めて、全角・半角が混在したデータを一括で揃える方法で扱っています。

再発を防ぐための運用

一度直しても、Macから受け取るたびに起きるなら、運用で防ぐほうが確実です。

  1. やり取りするファイル名に、濁点を含む日本語を使わない(半角英数字とハイフンにする)
  2. 受け取った側で、フォルダごとに一括でNFC化してから使う(コピーを取ってから)
  3. システムに登録するファイル名は、登録前に文字数・バイト数で確認する
  4. ZIPで渡す場合は、受け取り側の環境で正しく展開できるか、事前に1件だけ試す

Git管理するプロジェクトでは、macOSとの併用時にファイル名の正規化が問題になることがあり、core.precomposeunicode という設定が用意されています。通常はMac版のGitが自動で設定するとされていますが、チーム内にMacとWindowsが混在している場合は、設定値を確認しておくと安心です(詳細はGitの公式ドキュメントをご確認ください)。

まとめ

  1. 濁点が分離して見えるのは、NFD(分解)とNFC(合成)の違いで、データが壊れているわけではない
  2. 見た目では判断できないので、文字数カウント、差分比較、URLエンコードで確認する
  3. 直すときは、PowerShellやNode.jsでNFCに変換する。実行前にフォルダのコピーを取る
  4. 落とし穴は、同名ファイルの衝突、バイト数の増加、参照の切れ、コピペによる再混入
  5. 再発を防ぐには、やり取りするファイル名を半角英数字にするのが最も確実

この記事は、一般的な整理と筆者の動作確認(Windows上)に基づくものです。ご利用の環境(Macのバージョン、ファイルシステム、共有サービス)によって挙動が異なる場合があります。重要なファイルを扱う前には、必ずバックアップを取ってから作業してください。

この記事で使うツール

関連記事