「invalid non-printable character U+3000」エラーの原因と解決方法

「invalid non-printable character U+3000」エラーの原因と解決方法

invalid non-printable character U+3000
syntax error: invalid non-printable character U+3000 in identifier

日本語環境で開発しているエンジニアが特に遭遇しやすいエラーです。見た目はただのスペースに見えるのにエラーになるという状況から、原因の特定に時間がかかりやすいのが特徴です。

本記事では以下の疑問に答えます。

  • U+3000 とは何か・なぜ混入するのか
  • どうやって見つけて削除するか
  • Go・Python・JavaScript・SQL・シェルスクリプトでの対処法
  • エディタの設定で予防する方法
  • CI/CD で自動検出する方法


目次

結論:先に答えを出す

# ① ファイルに U+3000(全角スペース)が含まれているか確認
grep -P "\x{3000}" ファイル名
grep -rn $'\xe3\x80\x80' .   # UTF-8 バイト列で検索

# ② 行番号付きで確認
grep -Pn "\x{3000}" ファイル名

# ③ sed で全角スペースを半角スペースに置換
sed -i 's/\xe3\x80\x80/ /g' ファイル名

# ④ 全角スペースを削除(スペースに変換せず除去)
sed -i 's/\xe3\x80\x80//g' ファイル名

# ⑤ ディレクトリ全体を一括修正
grep -rl $'\xe3\x80\x80' . | xargs sed -i 's/\xe3\x80\x80/ /g'

U+3000 とは何か

文字の正体

U+3000IDEOGRAPHIC SPACE(表意文字スペース)、いわゆる全角スペースです。

U+0020  →  通常の半角スペース(ASCII)
U+3000  →  全角スペース(日本語・中国語・韓国語環境で使われる)

見た目はほぼ同じですが、コンピュータ上は全く異なる文字です。多くのプログラミング言語はソースコード内の全角スペースを**非表示文字(non-printable character)**として扱いエラーにします。

UTF-8 でのバイト表現

半角スペース  U+0020  → 0x20           (1バイト)
全角スペース  U+3000  → 0xE3 0x80 0x80 (3バイト)

よく混入する他の不可視文字

U+3000 以外にも問題になる不可視文字があります。

コードポイント名称主な発生源
U+3000IDEOGRAPHIC SPACE(全角スペース)日本語IME・日本語テキストのコピペ
U+00A0NO-BREAK SPACE(ノーブレークスペース)Web ページからのコピペ
U+200BZERO WIDTH SPACE(ゼロ幅スペース)Web ページ・Word からのコピペ
U+200CZERO WIDTH NON-JOINERアラビア語・ペルシャ語テキスト
U+200DZERO WIDTH JOINER絵文字の結合文字
U+FEFFBOM(バイトオーダーマーク)Windows のテキストエディタ
U+2028LINE SEPARATORWeb ページ・JSON
U+2060WORD JOINEROffice ドキュメント

なぜ混入するのか

主な発生原因

1. 日本語 IME の誤入力

日本語入力モードのままスペースを押すと全角スペースが入力されます。特にコメントや文字列を日本語で書いた後、うっかりそのままコードを書くと混入します。

// コメントを日本語で書いた後、IMEをオフにせずスペースを押す
func main() {  // ← func の後が全角スペース

2. 日本語テキストのコピー&ペースト

ドキュメント・メール・Slack・Web ページからコードをコピーすると、全角スペースがそのまま混入することがあります。

3. Word・Google Docs からのコピー

Office 系ツールは全角スペースや特殊スペースを多用します。

4. AI ツールの出力

ChatGPT・Claude などの AI が生成したコードをコピーする際、まれに全角スペースが混入することがあります。

5. Windows 環境で作成されたファイル

CRLF 改行や BOM(U+FEFF)が混入しやすい環境です。


検出方法

grep で検索

# 全角スペースを含む行を表示(UTF-8 バイト列で指定)
grep -n $'\xe3\x80\x80' ファイル名

# PCRE 正規表現で指定(-P オプション)
grep -Pn "\x{3000}" ファイル名

# ディレクトリ全体を再帰検索
grep -rn $'\xe3\x80\x80' .
grep -rPn "\x{3000}" .

# ファイル名だけ表示
grep -rl $'\xe3\x80\x80' .

# 複数の不可視文字をまとめて検索
grep -Pn "[\x{3000}\x{00A0}\x{200B}\x{FEFF}]" ファイル名

cat・od・hexdump で確認

# 制御文字・特殊文字を可視化
cat -A ファイル名
cat -v ファイル名

# 16進ダンプで確認(E3 80 80 が全角スペース)
od -c ファイル名 | grep -A1 "E3 80 80"
hexdump -C ファイル名 | grep "e3 80 80"

# xxd で確認
xxd ファイル名 | grep "e380 80"

Python で確認

# ファイルの中身を確認
with open("ファイル名", encoding="utf-8") as f:
    for i, line in enumerate(f, 1):
        if '\u3000' in line:
            print(f"行 {i}: {repr(line)}")

# 全不可視文字を確認
import unicodedata
with open("ファイル名", encoding="utf-8") as f:
    for i, line in enumerate(f, 1):
        for j, char in enumerate(line):
            if unicodedata.category(char) in ('Zs', 'Cc', 'Cf'):
                if char not in (' ', '\n', '\r', '\t'):
                    print(f"行 {i} 文字 {j}: U+{ord(char):04X} ({unicodedata.name(char, '?')})")

Node.js で確認

const fs = require('fs');

const content = fs.readFileSync('ファイル名', 'utf8');
const lines = content.split('\n');

lines.forEach((line, i) => {
  if (line.includes('\u3000')) {
    console.log(`行 ${i + 1}: ${JSON.stringify(line)}`);
  }
});

削除・修正方法

sed で置換・削除

# 全角スペースを半角スペースに置換
sed -i 's/\xe3\x80\x80/ /g' ファイル名

# 全角スペースを削除
sed -i 's/\xe3\x80\x80//g' ファイル Parameter名

# macOS の場合(GNU sed との違い)
sed -i '' 's/'"$(printf '\xe3\x80\x80')"'/ /g' ファイル名

# ディレクトリ全体を一括修正
grep -rl $'\xe3\x80\x80' . | xargs sed -i 's/\xe3\x80\x80/ /g'

# 特定の拡張子だけ修正
grep -rl $'\xe3\x80\x80' --include="*.go" . \
  | xargs sed -i 's/\xe3\x80\x80/ /g'

Python で修正

import re

def fix_invisible_chars(filepath):
    with open(filepath, encoding="utf-8") as f:
        content = f.read()

    # 全角スペースを半角スペースに
    fixed = content.replace('\u3000', ' ')

    # その他の不可視スペースも対応
    fixed = fixed.replace('\u00a0', ' ')  # NO-BREAK SPACE
    fixed = fixed.replace('\u200b', '')   # ZERO WIDTH SPACE(削除)
    fixed = fixed.replace('\ufeff', '')   # BOM(削除)

    with open(filepath, "w", encoding="utf-8") as f:
        f.write(fixed)

    print(f"修正しました: {filepath}")

fix_invisible_chars("ファイル名.py")
# ディレクトリ全体を修正
import os
import glob

for filepath in glob.glob("**/*.py", recursive=True):
    fix_invisible_chars(filepath)

tr コマンドで削除

# tr は Unicode の直接指定が難しいため cat + python で対応
cat ファイル名 | python3 -c "
import sys
content = sys.stdin.read()
print(content.replace('\u3000', ' '), end='')
" > 修正後ファイル名

VS Code で一括置換

Ctrl+H(Windows/Linux)または Cmd+H(macOS)で置換ダイアログを開く

検索欄に全角スペースを貼り付ける(または正規表現 \u3000 を使う)
置換欄に半角スペース(または空白)を入力
「ファイル内を置換」または「すべてのファイルで置換」をクリック

正規表現モードを有効にして \u3000 で検索することもできます。


言語別のエラーと対処法

Go

Go は全角スペースに最も厳しい言語のひとつです。

// ❌ エラーになるコード(全角スペースが混入)
func main() {  // func の後が全角スペース
    fmt.Println("Hello")
}
// syntax error: invalid non-printable character U+3000 in identifier
# Go ファイルの全角スペースを検出
grep -Pn "\x{3000}" *.go

# gofmt で整形(コード構造の問題は直らないが、スペースの確認はできる)
gofmt -e ファイル名.go

# 修正
sed -i 's/\xe3\x80\x80/ /g' ファイル名.go

Go ではビルド時・go vet 実行時にエラーが出るため、CI での早期検出が効果的です。


Python

# ❌ 全角スペースがインデントに混入
def hello():       # def の後が全角スペース
    print("Hello")  # インデントが全角スペース

# SyntaxError: invalid character ' ' (U+3000)
# または
# IndentationError: unexpected indent
# ✅ 検出スクリプト
import ast
import sys

def check_file(filepath):
    with open(filepath, encoding="utf-8") as f:
        source = f.read()
    if '\u3000' in source:
        lines = source.split('\n')
        for i, line in enumerate(lines, 1):
            if '\u3000' in line:
                print(f"{filepath}:{i}: 全角スペースが含まれています")
                print(f"  {repr(line)}")
        return True
    return False

Python 3.12 以降はエラーメッセージが改善され、より分かりやすくなっています。


JavaScript / TypeScript

// ❌ 変数名や演算子の前後に全角スペース
const x = 1;  // const の後が全角スペース
// SyntaxError: Invalid or unexpected token

// ❌ テンプレートリテラル内の全角スペースは文字列として残る(エラーにはならないが意図しない動作)
const msg = `Hello World`;  // ← 全角スペースが文字列に含まれる
# ESLint で検出する設定
# .eslintrc.json
{
  "rules": {
    "no-irregular-whitespace": "error"
  }
}

# ESLint を実行
npx eslint ファイル名.js
// TypeScript のコンパイラオプション
// tsconfig.json で strict モードを有効にすると一部検出できる
// ただし全角スペースの完全な検出は ESLint が確実

SQL

-- ❌ カラム名・テーブル名・キーワードに全角スペースが混入
SELECT * FROM users;  -- キーワードの前後が全角スペース
-- ERROR: syntax error at or near " "

-- ❌ WHERE 句での混入
WHERE name = 'Alice';
# SQL ファイルの検出と修正
grep -Pn "\x{3000}" *.sql
sed -i 's/\xe3\x80\x80/ /g' *.sql

PostgreSQL・MySQL ともに SQL 文中の全角スペースはエラーになります。ただし文字列リテラルの中(' ' など)は文字として扱われます。


シェルスクリプト(bash / zsh)

# ❌ コマンドの前後に全角スペース
echo "Hello"   # echo の後が全角スペース
# bash: echo : command not found

# ❌ 変数名に全角スペース
MY_VAR = "value"
# bash: MY_VAR : command not found

# ❌ if 文の条件
if [ "$x" = "1" ]; then
# 検出と修正
grep -Pn "\x{3000}" *.sh
sed -i 's/\xe3\x80\x80/ /g' *.sh

# shellcheck でシェルスクリプトを静的解析
sudo apt install shellcheck
shellcheck *.sh

YAML / JSON

# ❌ YAML のキーや値に全角スペース
name: Alice   # コロンの後が全角スペース
age: 30

# yamllint で検出
yamllint ファイル名.yaml
// JSON の文字列値内の全角スペースはエラーにならないが意図しない動作の原因になる
{
  "name": "Alice Bob"  // ← 全角スペースが含まれている
}
# JSON の検出
python3 -c "
import json, sys
with open('ファイル名.json') as f:
    content = f.read()
if '\u3000' in content:
    print('全角スペースが含まれています')
    for i, line in enumerate(content.split('\n'), 1):
        if '\u3000' in line:
            print(f'  行 {i}: {repr(line)}')
"

Dockerfile

# ❌ Dockerfile に全角スペースが混入
RUN apt-get update   # RUN の後が全角スペース
# OCI runtime exec failed: ...
# Dockerfile の検出と修正
grep -Pn "\x{3000}" Dockerfile
sed -i 's/\xe3\x80\x80/ /g' Dockerfile

# hadolint で Dockerfile を静的解析
docker run --rm -i hadolint/hadolint < Dockerfile

エディタの設定で予防する

VS Code

// settings.json
{
  // 全角スペースなどの不可視文字を可視化
  "editor.renderWhitespace": "all",

  // 問題のある文字をハイライト
  "editor.unicodeHighlight.ambiguousCharacters": true,
  "editor.unicodeHighlight.invisibleCharacters": true,
  "editor.unicodeHighlight.nonBasicASCII": false,

  // 日本語ファイルでも全角スペースを警告
  "editor.unicodeHighlight.allowedLocales": {},

  // 保存時に末尾スペースを削除
  "files.trimTrailingWhitespace": true
}

VS Code では U+3000 などの問題文字にカーソルを当てると警告が表示されます。

Vim / Neovim

" 全角スペースを可視化(~/.vimrc)
highlight ZenkakuSpace cterm=underline ctermfg=lightblue guibg=darkgray
match ZenkakuSpace / /

" autocmd で常に有効化
augroup ZenkakuSpace
  autocmd!
  autocmd ColorScheme * highlight ZenkakuSpace cterm=underline ctermfg=lightblue guibg=darkgray
  autocmd VimEnter,WinEnter,BufRead * let w:m1=matchadd('ZenkakuSpace', ' ')
augroup END
-- Neovim(init.lua)
vim.api.nvim_set_hl(0, 'ZenkakuSpace', { bg = '#3d3d3d', underline = true })
vim.fn.matchadd('ZenkakuSpace', ' ')

JetBrains IDE(IntelliJ・GoLand・PyCharm)

設定 → Editor → Code Style → General
→ "Other" タブ → "Show different font for non-ASCII characters" を有効化

または

設定 → Editor → Inspections → "Invisible characters" を有効化

Emacs

;; 全角スペースをハイライト
(require 'whitespace)
(setq whitespace-style '(face tabs tab-mark spaces space-mark))
(setq whitespace-space-regexp "\\(\u3000+\\)")
(global-whitespace-mode 1)

CI/CD で自動検出する

GitHub Actions

# .github/workflows/check-encoding.yml
name: Check for invalid characters

on: [push, pull_request]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Check for full-width spaces (U+3000)
        run: |
          # 全角スペースが含まれているファイルを検出
          FILES=$(grep -rl $'\xe3\x80\x80' --include="*.go" \
                                            --include="*.py" \
                                            --include="*.js" \
                                            --include="*.ts" \
                                            --include="*.sh" \
                                            --include="*.sql" \
                                            . 2>/dev/null || true)
          if [ -n "$FILES" ]; then
            echo "❌ 全角スペース(U+3000)が含まれているファイルが見つかりました:"
            echo "$FILES"
            echo ""
            echo "以下のコマンドで修正してください:"
            echo "  grep -rl \$'\\xe3\\x80\\x80' . | xargs sed -i 's/\\xe3\\x80\\x80/ /g'"
            exit 1
          fi
          echo "✅ 全角スペースは見つかりませんでした"

      - name: Check for other invisible characters
        run: |
          # BOM・ゼロ幅スペースなども検出
          if grep -Prl "[\x{FEFF}\x{200B}\x{200C}\x{200D}]" \
               --include="*.go" --include="*.py" --include="*.js" .; then
            echo "❌ 不可視文字が含まれているファイルが見つかりました"
            exit 1
          fi
          echo "✅ その他の不可視文字は見つかりませんでした"

pre-commit フック

# .git/hooks/pre-commit
#!/bin/bash

# コミット対象のファイルに全角スペースが含まれているか確認
FILES=$(git diff --cached --name-only --diff-filter=ACM)

FOUND=0
for FILE in $FILES; do
  if [ -f "$FILE" ] && grep -Pq "\x{3000}" "$FILE"; then
    echo "❌ 全角スペースが含まれています: $FILE"
    grep -Pn "\x{3000}" "$FILE" | head -5
    FOUND=1
  fi
done

if [ "$FOUND" -eq 1 ]; then
  echo ""
  echo "コミットをブロックしました。以下のコマンドで修正してください:"
  echo "  grep -rl \$'\\xe3\\x80\\x80' . | xargs sed -i 's/\\xe3\\x80\\x80/ /g'"
  exit 1
fi
chmod +x .git/hooks/pre-commit

pre-commit フレームワークを使う場合

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: mixed-line-ending
      - id: trailing-whitespace

  - repo: local
    hooks:
      - id: no-fullwidth-space
        name: No full-width space (U+3000)
        language: pygrep
        entry: "\u3000"
        types: [text]
pip install pre-commit
pre-commit install

トラブルシューティング

grep で検索できない

# 環境によって正規表現の書き方が異なる
# GNU grep(Linux)
grep -Pn "\x{3000}" ファイル名

# macOS のデフォルト grep(BSD grep)は -P 非対応
# → Homebrew で GNU grep をインストール
brew install grep
ggrep -Pn "\x{3000}" ファイル名

# または perl で代替
perl -ne 'print "$.: $_" if /\x{3000}/' ファイル名

# または python で代替
python3 -c "
with open('ファイル名', encoding='utf-8') as f:
    for i, line in enumerate(f, 1):
        if '\u3000' in line:
            print(f'{i}: {repr(line)}')
"

sed で置換できない(macOS)

# macOS の sed は GNU sed と挙動が異なる
# ❌ Linux では動くが macOS では動かない
sed -i 's/\xe3\x80\x80/ /g' ファイル名

# ✅ macOS 対応(-i の後に空文字列が必要)
sed -i '' 's/'"$(printf '\xe3\x80\x80')"'/ /g' ファイル名

# ✅ または Homebrew の GNU sed を使う
brew install gnu-sed
gsed -i 's/\xe3\x80\x80/ /g' ファイル名

# ✅ または Python で置換
python3 -c "
import sys
path = sys.argv[1]
with open(path, encoding='utf-8') as f:
    content = f.read()
with open(path, 'w', encoding='utf-8') as f:
    f.write(content.replace('\u3000', ' '))
print(f'修正完了: {path}')
" ファイル名

エラーが出る行が特定できない

# エラーメッセージに行番号がない場合
# ファイル全体を16進ダンプして確認
hexdump -C ファイル名 | grep -B2 -A2 "e3 80 80"

# Python で詳細な位置を表示
python3 -c "
with open('ファイル名', encoding='utf-8') as f:
    for lineno, line in enumerate(f, 1):
        for colno, char in enumerate(line, 1):
            if char == '\u3000':
                print(f'行 {lineno} 列 {colno}: U+3000 を検出')
"

修正後もエラーが出る

# 全角スペース以外の不可視文字が残っている可能性
python3 -c "
import unicodedata
with open('ファイル名', encoding='utf-8') as f:
    for lineno, line in enumerate(f, 1):
        for colno, char in enumerate(line, 1):
            cat = unicodedata.category(char)
            if cat in ('Zs', 'Cf') and char not in (' ', '\t'):
                name = unicodedata.name(char, f'U+{ord(char):04X}')
                print(f'行 {lineno} 列 {colno}: {name} (U+{ord(char):04X})')
"

# BOM が残っている場合
file ファイル名
# UTF-8 Unicode (with BOM) text ← BOM あり

# BOM を削除
sed -i '1s/^\xef\xbb\xbf//' ファイル名

よくある質問(FAQ)

Q1. 全角スペースとは何ですか?

日本語・中国語・韓国語(CJK)テキストで使われるスペースで、半角スペース(U+0020)の2倍の幅を持ちます。日本語 IME を使う環境では、スペースキーを押すと全角スペースが入力される設定になっていることがあります。

Q2. なぜ見た目で分からないのですか?

多くのエディタやフォントでは全角スペースと半角スペースをほぼ同じ見た目で表示します。特に等幅フォントでは区別がつきにくいです。VS Code の editor.unicodeHighlight 設定や Vim のハイライト設定で可視化することをおすすめします。

Q3. 全角スペースが入力されないようにするには?

IME の設定で、スペースキーを常に半角スペースにする設定があります。

Windows(Microsoft IME):
  IME プロパティ → 詳細設定 → 「スペース入力」を「半角」に設定

macOS(日本語入力):
  システム設定 → キーボード → 入力ソース
  → 「スペースバーの動作」を「スペース」に設定

Q4. 文字列の中の全角スペースはエラーになりますか?

言語によって異なります。

// Go:文字列リテラル内は OK
s := "Hello World"  // ← エラーにならない(文字列の中)
fmt. Println(s)     // ← エラー(コード中の全角スペース)
# Python:文字列内は OK、コード中はエラー
s = "Hello World"   # ← OK(文字列の中)
x = 1               # ← SyntaxError(コード中)

Q5. U+3000 以外にも気をつけるべき文字はありますか?

よく問題になるのは以下です。

# まとめて検索
grep -Pn "[\x{3000}\x{00A0}\x{200B}\x{FEFF}\x{2028}\x{2060}]" ファイル名

特に Web ページやドキュメントからコピーした場合は U+00A0(ノーブレークスペース)や U+200B(ゼロ幅スペース)が混入しやすいです。

Q6. git diff で全角スペースを検出できますか?

# git diff でも確認できる
git diff | grep -P "\x{3000}"

# git log で特定コミットを確認
git show コミットハッシュ | grep -P "\x{3000}"

# git grep でリポジトリ全体を検索
git grep -Pn "\x{3000}"

まとめ

「invalid non-printable character U+3000」は全角スペースがソースコードに混入することで発生します。

検出:

grep -Pn "\x{3000}" ファイル名          # 単一ファイル
grep -rPn "\x{3000}" .                  # ディレクトリ全体

修正:

sed -i 's/\xe3\x80\x80/ /g' ファイル名            # 単一ファイル
grep -rl $'\xe3\x80\x80' . \
  | xargs sed -i 's/\xe3\x80\x80/ /g'            # 一括修正

予防:

  1. VS Code で editor.unicodeHighlight.invisibleCharacters: true を設定
  2. Vim で全角スペースをハイライト
  3. IME の設定でスペースを常に半角に
  4. pre-commit フックで自動検出
  5. CI/CD で grep -rP "\x{3000}" を実行

日本語環境での開発では避けて通れない問題ですが、エディタの設定と CI での自動検出を組み合わせることで、混入を防ぐことができます。


参考リンク

文字コード関連

ツール

関連記事(本サイト)


本記事は2026年6月時点の情報をもとに、Ubuntu 24.04 LTS・macOS Sequoia・Go 1.22・Python 3.12 での動作確認に基づき作成しています。環境によってコマンドの挙動が異なる場合があるため、最新情報は各公式ドキュメントをご確認ください。