主要エディタ別:不可視文字の見える化と自動削除(VS Code/Word/Google Docs)
主要エディタ別:不可視文字の見える化と自動削除(VS Code/Word/Google Docs)
“原因が分からないレイアウト崩れ”“検索に引っかからない文字列”“diff が増える”──それ、ゼロ幅文字やBidi制御文字が紛れ込んでいるかもしれません。本記事では VS Code/Microsoft Word/Google ドキュメント での 見える化→検出→安全な置換→自動化 までを手順つきで解説します。最短で一括クリーンしたい場合は Invisible Cleaner も併用してください。
大枠の進め方(共通フロー)
- 見える化:不可視文字を視認できる設定・拡張をON
- 検出:正規表現やコードポイントでヒットさせる
- 部分置換:意味が変わらないことを確認しながら少しずつ
- 一括クリーン:バックアップを確保してから実行
- 自動化:保存時・コミット時に走る処理を組み込む
VS Code での対処
1) 見える化の設定
設定(Ctrl/Cmd+,)
→ 次を有効化editor.renderControlCharacters
:制御文字を表示editor.renderWhitespace
= "all"`:空白類を可視化editor.unicodeHighlight.invisibleCharacters
= true:不可視文字をハイライトeditor.unicodeHighlight.ambiguousCharacters
= true`:まぎらわしい文字を警告
- 便利な拡張(任意):
- Gremlins Tracker(不可視文字を強調)
- Code Spell Checker(表層の綴り異常も拾う)
2) 検出(検索 → 正規表現ON)
検索パネル(Ctrl/Cmd+F)で「正規表現」をONにして次を利用:
[] # ZWSP,ZWNJ,ZWJ,BOM
|[--] # 代表的なBidi制御文字
注意:むやみに
\p{Cf}
を全削除しないこと。言語依存の整形に必要なケースがあります。
3) 安全な置換
- まずは ヒット箇所を1つずつ確認 して削除(置換後に崩れがないかプレビュー)。
- 文字数やカーソル位置のズレが気になる場合は、ZWSPを 半角スペース に一時変換 → 意味が変わらないことを確認 → その後で削除、の二段階が安全。
4) 保存時の自動クリーン(任意)
.vscode/settings.json
例:
{
"editor.unicodeHighlight.invisibleCharacters": true,
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"files.trimTrailingWhitespace": true
}
タスクや拡張を使って保存時に不可視文字を削除するスクリプトを呼ぶ方法もあります(対象拡張子を限定するのがコツ)。
5) Git フックでの検出(任意)
プロジェクト直下に pre-commit
を置き、不可視文字が見つかったら警告する例(Node.js):
#!/usr/bin/env bash
# staged テキストに不可視文字が含まれていないか検査
files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(txt|md|js|ts|tsx|css|html)$')
if [ -z "$files" ]; then exit 0; fi
pattern='[--]'
node -e "
const fs=require('fs');
const { execSync } = require('child_process');
let bad=[];
'${files}'.split('\n').filter(Boolean).forEach(f=>{
const c=fs.readFileSync(f,'utf8');
if (c.match(${pattern.toString()})) bad.push(f);
});
if (bad.length){ console.error('Invisible chars found in:\n'+bad.join('\n')); process.exit(1); }
"
Microsoft Word での対処
1) 見える化
- ホーム → ¶(編集記号の表示/非表示) をON。
- 行や段落、空白の状態を可視化してから操作します。
2) 検出(高度な検索)
Word は Unicodeコードポイントの検索 に対応しています。Ctrl+H
→ 「検索する文字列」に次のように入力:
^u200B
(ZWSP)^u200C
(ZWNJ)^u200D
(ZWJ)^uFEFF
(BOM)
Bidi 制御の代表(例):
^u202A
(LRE) /^u202B
(RLE) /^u202C
(PDF)^u202D
(LRO) /^u202E
(RLO)^u200E
(LRM) /^u200F
(RLM)
置換は 空欄(削除)を基本に、意味が変わる恐れがある場合はスペースや可視記号に一時置換→確認後に削除する二段階を推奨。
3) 範囲を限定して少しずつ
- 章ごと・段落ごとに検索→置換を繰り返し、レイアウトが崩れないか都度確認。
- 変更前のバージョンを「別名保存」しておくと復元が容易。
Google ドキュメント での対処
1) 見える化
- 標準では不可視文字の明示表示が弱いため、まずは [
Ctrl/Cmd+F
] で検索を用意。 - ZWSP などを一旦 クリップボードに保持(例:本記事末尾の付録からコピー)し、検索欄に貼り付けてヒットさせます。
2) Apps Script で検出→置換(推奨)
ドキュメントに紐づく 拡張機能 → Apps Script を開き、次を貼り付けて保存:
function cleanInvisibleChars() {
const doc = DocumentApp.getActiveDocument();
const body = doc.getBody();
const pairs = [
['\u200B', ''], // ZWSP
['\u200C', ''], // ZWNJ
['\u200D', ''], // ZWJ
['\uFEFF', ''], // BOM
['[\u202A-\u202E\u2066-\u2069]', ''] // 代表的Bidi
];
pairs.forEach(([pattern, replacement]) => {
const re = new RegExp(pattern, 'g');
const text = body.getText();
const cleaned = text.replace(re, replacement);
if (text !== cleaned) {
body.clear();
body.appendParagraph(cleaned);
}
});
}
- 初回は コピーを作成 してテストするのが安全です。
- 置換結果が望ましくない場合は
Ctrl/Cmd+Z
で即座に戻せます。 - 文字ごとの挙動を確かめたいときは、置換文字を
''
ではなく' '
(半角スペース)に一時変更し、差分を確認してから再実行すると安心。
3) 共同編集の注意
- 他メンバーの貼り付けで再混入しやすいので、貼り付けはプレーンテキスト推奨 のルールを共有。
- 重要なテンプレートは クリーン済みの原本 を用意し、複製して使う。
付録:よく使う検出パターン・素材
正規表現(JS/PCRE系)
[] # ZWSP/ZWNJ/ZWJ/BOM
|[--] # 代表的なBidi(LRE/RLE/LRO/RLO/PDF/LRI/RLI/FSI/PDI)
検索用の「実体」文字(コピーして使う)
- ZWSP:(←ここに不可視の U+200B が入っています)
- ZWNJ:(U+200C)
- ZWJ:(U+200D)
- LRM:(U+200E)
- RLM:(U+200F)
- BOM:(U+FEFF)
画面上では見えにくいので、選択→コピー で使ってください(ヒット件数で存在を確認できます)。
失敗しないコツ(共通)
- 段階的 に:検出→部分置換→全体置換
- バックアップ:原本を残す/バージョン管理にコミット
- プレビュー重視:置換後に検索・レイアウト・リンクを必ず再確認
- 自動化は“最後に”:手作業で安全が確認できてから保存時・CIに組み込み
まとめ
不可視文字は「見えない」だけでなく、検索・差分・パース のあらゆる工程を乱します。
VS Code/Word/Google ドキュメントそれぞれで 見える化 と 最小限の置換 を実施し、慣れてきたら保存時やCIでの 自動チェック を導入しましょう。急ぎの時は Invisible Cleaner で状態を可視化してから、必要な箇所だけ安全にクリーンするのが最短です。