Windows の Vim/Neovim で UTF-8 の文字化けを診断する:エンコーディング、BOM、端末、フォント

「文字化け」は診断結果ではありません。同じ症状でも、ディスク上のバイト列、Vim の読み込み変換、端末のコードページ、フォントにないグリフ、改行コード、クリップボード、リモートセッションなど原因はさまざまです。まず証拠を保存し、コピーで試してください。元のエンコーディングが確定するまで原本へ書き込まないでください。

1. まず各レイヤーを分ける

レイヤーVim/Windows で確認する証拠よくある誤診
ファイルのバイトエンコーディング'fileencoding''fileencodings'、BOM、16 進バイト読めない文字をすべて UTF-8 の問題と呼ぶ
Vim の内部エンコーディング'encoding'変更すれば読み込み済みバッファが再デコードされると思う
読み込み時の検出順序'fileencodings'Vim がすべての旧式エンコーディングを確実に自動判定できると思う
現在のバッファの出力エンコーディング'fileencoding'変更して保存し、出力変換を再読み込みと取り違える
BOM'bomb'ucs-bomBOM、エンコーディング、内容を一つのものとして扱う
改行コード'fileformat''fileformats'CRLF/LF や表示された ^M を文字破損と判断する
端末またはコンソール端末ホスト、chcp、入出力 APIコードページのコマンドでディスク上のファイルを直そうとする
フォントとグリフGUI/端末フォント、カーソル位置での :asciiコードポイントは正しいのにフォントに字形がなく、再エンコードする
ロケールとメッセージ言語v:lang、プロセス環境、Windows のシステムロケールUI の言語設定をファイルエンコーディング設定とみなす
クリップボードとリモートセッション+/* レジスタ、provider、SSH/RDP/WSL/マルチプレクサローカルファイルは正しいのに貼り付けや遠隔表示の問題でファイルを編集する

最初に「バイトが誤っているのか、デコードが誤っているのか、表示が誤っているのか」を判断します。別の信頼できるツールで正しく表示されることは比較材料になりますが、それだけでエンコーディングが証明されるわけではありません。

2. Vim の三つのエンコーディングオプション

  • 'encoding'Vim 内部で使う文字エンコーディングです。現在の Vim は Windows で UTF-8 が既定です。変更しても読み込み済みのテキストは再解釈されず、公式ヘルプは非 ASCII テキストが無効になる可能性を警告しています。通常は起動時の UTF-8 のままにします。
  • 'fileencodings'既存ファイルを開くときに順番に試すグローバルなリストです。検出エラーがなかった最初の候補が選ばれ、バッファの 'fileencoding' になります。ucs-bom は Unicode 候補より前に置きます。latin1 のように任意のバイトを受理する 8 ビットのフォールバックは最後に置かないと、後続候補が試されません。
  • 'fileencoding'現在のバッファのファイルエンコーディングです。書き込み時の変換を制御します。直接変更してもディスクのバイトは再読み込みされません。指定エンコーディングで読むには ++enc を使います。

自動検出には根本的な限界があります。ASCII は多くのエンコーディングで有効であり、多くの旧式 8 ビットエンコーディングには確実に区別できるほど無効なバイトパターンがありません。出所、BOM、プロトコルの規約、または信頼できるサンプルがなければ、「正しく見える」だけでは十分な証拠になりません。

3. まず読み取り専用の棚卸しをする

問題のあるバッファで次のコマンドを実行します。verbose は、そのオプションを最後に変更したスクリプトの場所を示します。$MYVIMRC は実際に読み込まれたユーザー設定を示すため、インストール先を推測せずに済みます。

:version
:echo $MYVIMRC
:echo exists('+termencoding')
:echo has('gui_running')
:echo has('clipboard')
:echo v:lang
:set encoding? fileencoding? fileencodings?
:set bomb? fileformat? fileformats? binary?
:set clipboard? guifont?
:verbose set encoding?
:verbose setlocal fileencoding?
:verbose set fileencodings?
:verbose setlocal bomb?
:verbose setlocal fileformat?
:scriptnames

出力を記録してください。ただし公開する前に、ユーザー名、パス、リモートホスト名、プロジェクト名を削除します。$MYVIMRC が空なら :version で Vim の検索先を確認します。Neovim では :echo stdpath('config') でユーザー設定ディレクトリを確認できます。ユーザー設定を優先し、インストールディレクトリのシステム設定を既定の編集対象にしないでください。

4. 独立したバイト証拠を保存する

自動整形や自動保存を行うツールを閉じます。PowerShell でバイト同一のテストコピーを作り、ハッシュを記録します。プレースホルダーは、調査権限のある実際のファイルに置き換えてください。

$SourcePath = "FILE_TO_INSPECT"
$TestPath = "$SourcePath.encoding-test-copy"
if (Test-Path -LiteralPath $TestPath) { throw "Choose a new test-copy path" }
Copy-Item -LiteralPath $SourcePath -Destination $TestPath -ErrorAction Stop
Get-FileHash -Algorithm SHA256 -LiteralPath $SourcePath
Get-FileHash -Algorithm SHA256 -LiteralPath $TestPath
Format-Hex -Path $TestPath | Select-Object -First 1
chcp
Get-Culture
Get-WinSystemLocale

二つのハッシュは一致するはずです。Format-Hex の先頭行で UTF-8 や UTF-16 の BOM が判明することがありますが、BOM がないから UTF-8 ではないとはいえません。chcp が示すのは現在のコンソールコードページだけで、ファイルエンコーディングの検出器ではありません。「試しに」先に chcp 65001 を実行しないでください。その後に起動するコンソールプログラムには影響しますが、ファイルのバイトを書き換えも証明もしません。

5. 可逆なバッファ単位の再読み込みテスト

コピーだけでテストし、:write は実行しません。まず UTF-8 として読み込みます。

:edit ++enc=utf-8 FILE_TO_INSPECT.encoding-test-copy
:setlocal fileencoding? bomb? fileformat? modified?
:ascii
:quit

:ascii の前にカーソルを既知の文字へ移動し、コードポイントを記録します。出所情報が旧式の簡体字中国語 Windows エンコーディングだと明確に示す場合は、新しいセッションで同じコピーを CP936 としてテストします。

:edit ++enc=cp936 FILE_TO_INSPECT.encoding-test-copy
:setlocal fileencoding? bomb? fileformat? modified?
:ascii
:quit

二つのうち単に「中国語らしく見える」結果だけで決めないでください。ファイルを生成したシステム、リポジトリ、プロトコル、隣接ファイル、既知の文言、16 進バイトと照合します。候補のデコードで置換文字、変換エラー、説明できない制御文字が生じる場合や、部分ごとに別のエンコーディングが必要な場合は、書き込みを停止します。

6. BOM と改行コードは別の次元

'bomb' は、対応する Unicode エンコーディングで書き出すときに BOM を付けるかどうかを表します。'fileencodings' の先頭が ucs-bom なら Vim は BOM を検査し、その結果に基づいて 'bomb''fileencoding' を設定します。利用側の要件が不明なまま bomb または nobomb をグローバル設定しないでください。

'fileformat' は現在のバッファの行末を制御し、dos は通常 CRLF、unix は LF を表します。UTF-8、CP936、UTF-16 の選択とは無関係です。バージョン管理で全行が変更扱いになったり ^M が見えたりする場合は、'encoding' を繰り返し変更する前に改行ポリシーを調べます。

デジタル署名、チェックサム、アーカイブ、データベース、実行可能ファイル、プロトコルで固定された形式は、すべてのバイトに依存することがあります。画面表示が正しくても、テキストエディタで書き込まないでください。

7. 端末、コンソール、フォント

Vim の公式ヘルプは、Windows が Unicode 文字を渡すため Win32 GUI 版とコンソール版では 'termencoding' を使わないと説明しています。したがって、古い let &termencoding=&encoding は現在の Win32 Vim に対する一般的な修正ではありません。Windows 以外の端末版 Vim では、空の 'termencoding' は通常 'encoding' と同じ値を意味します。別の処理が必要なのは、非 UTF-8 の端末境界が検証できた場合だけです。

Windows Terminal は Unicode/UTF-8 に対応しますが、フォントにも対象のグリフが必要です。:ascii が期待するコードポイントを示すのに画面が四角、空白、置換グリフなら、ファイルを変換せず、対象文字を収録した端末または GUI フォントを選びます。GVim の 'guifont' は GUI にだけ作用し、端末 Vim のフォントは端末側で設定します。

同じマシンで GVim は正常でも端末 Vim が異常なら、端末ホスト、フォント、コードページ、Vim のビルドを比較します。chcp は一部の従来型コンソールアプリケーションに影響しますが、Unicode アプリケーションと Win32 Vim の挙動を一つのコードページ番号だけで説明することはできません。

8. ロケール、クリップボード、リモートセッション

メッセージ言語、入力方式、システムロケール、現在のコンソール、ファイルエンコーディングは関連しますが別物です。language messages が変えるのはメッセージだけです。旧記事のメニュー再読み込みや ambiwidth もファイルを再デコードしません。

直接入力は正しいのに別アプリからの貼り付けで壊れる場合は、Vim の +/* レジスタ、端末自身の貼り付け、クリップボード provider を別々にテストします。Neovim は provider 経由でシステムクリップボードへ接続します。SSH、WSL、端末マルチプレクサでは provider や OSC 52 の対応が異なることがあります。私的なファイル内容をオンラインの「エンコーディング検出」サイトへ貼り付けないでください。

リモートセッションには少なくとも、ローカル端末、転送、リモートロケール、リモートの Vim/Neovim 設定、リモートファイルのバイトという五つの境界があります。ローカルでは正常でも SSH/RDP で異常なら、リモート原本を変更する前に両端のバージョン、設定、フォント/端末、ハッシュを記録します。

9. 検証済みの Vim と Neovim の違い

項目Windows 上の VimNeovim
内部 'encoding'現在の Windows 既定は UTF-8。オプションとして残るが、読み込み済みテキストで安易に変更しない常に UTF-8 であり、切り替える修正手段ではない
'termencoding'Win32 GUI/コンソールでは不使用。ほかの端末ビルドでだけ関係する可能性がある削除済み。古い Vim 設定をコピーしない
'fileencoding'/'fileencodings'ファイル変換と候補順序を制御非 UTF-8 ファイルの変換と候補順序を引き続き制御
設定場所の確認$MYVIMRC:version$MYVIMRCstdpath('config')。通常は init.lua または init.vim
クリップボードビルド機能とレジスタに依存外部/内蔵 provider を使用。:checkhealth で確認できる

インストール済みバージョンの :help で存在を確認してからオプションを設定します。両エディタへの対応を理由に未知のオプションを黙って無視しないでください。実際の設定エラーが隠れます。

10. 最小限で失敗が見える設定変更

BOM 付き Unicode または UTF-8 だけを含むべきプロジェクトでは、コピーで検証後、次の保守的な設定を検討できます。旧式エンコーディングを推測しないため、不正な UTF-8 は問題として見えたままになり、調査を促します。

if !has('nvim')
  set encoding=utf-8
endif
set fileencodings=ucs-bom,utf-8

'fileencoding'chinese、CP936、その他の旧式エンコーディングへグローバル設定しないでください。旧式エンコーディングだと確認済みの資料群では、その正確なエンコーディングを最後の明示候補に加える前に、実際のコピーでテストします。単一バイトのフォールバックは任意のバイトを受け入れ、誤りを隠すことがあります。

termencodingambiwidth、メニュー再読み込み、メッセージ言語を一つの「UTF-8 修正」にまとめないでください。それぞれに独立した症状、証拠、ロールバック理由が必要です。

11. vimrc のバックアップ、検証、ロールバック

$MYVIMRC で実際に読み込まれたパスを取得し、設定を書き込む可能性があるすべての Vim インスタンスを終了してから、PowerShell でバックアップします。プレースホルダーのまま実行しないでください。

$ConfigPath = "PASTE_LOADED_CONFIG_PATH"
$BackupPath = "$ConfigPath.encoding-backup"
if (Test-Path -LiteralPath $BackupPath) { throw "Choose a new backup path" }
Copy-Item -LiteralPath $ConfigPath -Destination $BackupPath -ErrorAction Stop
Get-FileHash -Algorithm SHA256 -LiteralPath $ConfigPath
Get-FileHash -Algorithm SHA256 -LiteralPath $BackupPath

編集後に新しい Vim/Neovim プロセスを起動し、コピー上で第 3、5 節の棚卸しを繰り返します。:verbose set fileencodings? が意図した設定を示すことを確認します。UTF-8、BOM あり/なし、ASCII、既知の旧式エンコーディング、CRLF/LF、端末、GUI をテストしてください。

起動エラー、以前は正常だったファイルの悪化、または出力方針が不明な場合は、エディタを閉じてロールバックします。

$ConfigPath = "PASTE_LOADED_CONFIG_PATH"
$BackupPath = "$ConfigPath.encoding-backup"
Copy-Item -LiteralPath $BackupPath -Destination $ConfigPath -Force -ErrorAction Stop
Get-FileHash -Algorithm SHA256 -LiteralPath $ConfigPath

ユーザー設定が存在しなかった場合は、公式の起動ドキュメントでユーザーパスを確認し、「ファイルなし」というベースラインを記録します。Program Files の下に場当たり的なシステム設定を作らないでください。

12. 原本を上書きせず、新しいファイルへ変換する

元のエンコーディングが確定し、表示とコードポイントの検査に合格し、バックアップがある場合だけ、コピーを新しい出力先へ変換します。

:edit ++enc=cp936 FILE_TO_INSPECT.encoding-test-copy
:write ++enc=utf-8 FILE_TO_INSPECT.converted-utf8
:edit ++enc=utf-8 FILE_TO_INSPECT.converted-utf8
:setlocal fileencoding? bomb? fileformat?

これは原位置での修復ではありません。'bomb''fileformat' は出力へ影響するため、利用側の仕様に一致するか確認します。出力を開き直し、既知のテキスト、行数、異常文字、BOM、改行、下流テストを比較します。受け入れ完了までは原本とハッシュを保持します。すべての文字を表現できない旧式エンコーディングへの変換は情報を失う可能性があるため、強制せず停止してください。

13. 症状から証拠への診断表

症状最初に調べる層次に集める読み取り専用の証拠停止条件
信頼できるエディタでは読めるが Vim では読めないVim の検出/設定fileencoding?fileencodings?verbose set、ハッシュバッファが変更済み。まだ再読み込みしない
:ascii は正しいコードポイントだが四角が表示されるフォント/グリフGUI と端末のフォント、別の対応フォント再エンコードしない
GVim は正常、端末 Vim は異常端末/フォント/ビルド:versionchcp、端末設定ディスク上のエンコーディングを変えない
直接入力は正常、貼り付けは異常クリップボード/providerclipboard?、レジスタ、Neovim の :checkhealth私的内容を検出のためアップロードしない
ローカルは正常、SSH/RDP/WSL は異常リモートセッション境界両端のバージョン、ロケール、設定、端末、ハッシュリモート原本を上書きしない
BOM 付きファイルだけ正常BOM と検出順序bomb?、候補順序、先頭バイトBOM をグローバルに強制しない
^M または全行の行末変更改行コードfileformat?、リポジトリの改行規約文字コード変換の問題として扱わない
保存後にバイトまたは下流挙動が変わる出力エンコーディング/BOM/改行バックアップのハッシュ、fileencoding?bomb?fileformat?直ちに戻し、再保存しない

14. 必ず停止すべきファイルと状況

  • NUL または未知のバイナリヘッダーを含む、あるいは実行可能ファイル、アーカイブ、画像、データベース、フォント、暗号化コンテナである。
  • デジタル署名、固定ハッシュ、法的保全、ファームウェア用途、プロトコルフレーム形式、バイト完全一致のビルド要件がある。
  • 元のエンコーディングが不明で複数候補がもっともらしく見える、または混在エンコーディング/既存破損の疑いがある。
  • バッファに未保存変更があり、バイト同一コピーがない、または BOM と改行の要件を説明できない。
  • 変換で不正シーケンス、表現不能文字、置換文字が報告される、または下流テストが悪化する。
  • ファイルを所有していない、秘密を含む、またはリモートシステムでの変更権限とロールバック責任が不明である。

これらはファイル形式の管理者、データ所有者、または適切な復旧/フォレンジック担当者へエスカレーションします。まず元のバイト、ハッシュ、ツールバージョン、読み取り専用ログを保存してください。

15. 変更前チェックリスト

  • [ ] ファイルのバイト、内部エンコーディング、検出リスト、現在の出力エンコーディング、BOM、改行を区別した。
  • [ ] Vim/Neovim のバージョン、実際の設定パス、オプションの由来を記録した。
  • [ ] すべての再読み込みと変換を、バイト同一コピーから始めた。
  • [ ] chcp、UI 言語、フォント変更をファイル変換として説明していない。
  • [ ] 既知のテキスト、:ascii、16 進バイト、出所で候補エンコーディングを検証した。
  • [ ] GUI/端末、直接入力/クリップボード、ローカル/リモートの境界を個別にテストした。
  • [ ] vimrc にはハッシュ一致のバックアップ、新規プロセスでの検証、明確なロールバックがある。
  • [ ] 新しいパスに出力し、BOM、改行、異常文字、下流挙動を確認した。
  • [ ] バイナリ、署名付き、不明、混在エンコーディングのファイルへ書き込んでいない。
  • [ ] 受け入れ完了まで原本と証拠を保持している。

16. 公式資料

資料は 2026-09-01 に確認しました。Vim、Neovim、Windows、端末の挙動はバージョンで変わります。インストール済み環境の :help と最新の公式文書を基準にしてください。

17. 2011 年の原文アーカイブ(出所確認専用)

次のフェンスには source_export の可視本文全体を一字一句そのまま保存しています。末尾空白の正規化、リンク削除、私的値のマスキングはいずれも不要でした。過去の Windows のバックスラッシュパス、Vim 7.2 の設定、スマートクォート、コマンドは現行の推奨ではなく、不活性な証拠としてのみ残しています。

~~~~markdown

在Windows中安装了vim,打开文件乱码,在网上搜了一下,那些方法根本不管用。都是支持gbk编码的设置,可是我打开gbk编码根本就没有问题。

Table of Contents

Toggle

方案1

我用这个方法成功了!

在C:Program FilesVim_vimrc的最前面加入下面二行,如果没有这个文件,就建一个这个文件。

let &termencoding=&encoding

set fileencodings=utf-8,gbk,ucs-bom,cp936

记的保存哦,然后在用Vim打开看看,UTF8和GB2312都没有问题。

方案2

我用这个方案失败了!

简体中文

如果在简体中文windows下使用vim的情况下,又想用vim编辑utf-8格式的文件的话,则需要在vim的配置文件(vim7.2如果默认安装之后,配置文件就是vim目录下的那个“_vimrc”文件,用记事本或者其它编辑器打开它就可以编辑)里设置好如下四个选项:

set encoding=utf-8

set termencoding=gb2312

set fileencodings=ucs-bom,utf-8,chinese

if has(“win32”)

set fileencoding=chinese

else

set fileencoding=utf8

endif

set ambiwidth=double

source $VIMRUNTIME/delmenu.vim

source $VIMRUNTIME/menu.vim

language messages zh_CN.UTF-8

在_vimrc文件的最前面加上即可。

繁体中文

发一个繁体系统下的配置:

set encoding=utf-8

set termencoding=big5

set fileencodings=ucs-bom,utf-8,chinese

if has(“win32”)

set fileencoding=chinese

else

set fileencoding=utf8

endif

set ambiwidth=double

source $VIMRUNTIME/delmenu.vim

source $VIMRUNTIME/menu.vim

language messages zh_TW.UTF-8

~~~~

Leave a Reply