文字コードと安全なファイル確認|PC・ブラウザ・ファイルの基本
このページはプロモーション(広告)を含みます。
PC・ブラウザ・ファイルの基本(初級・読む25分+演習30分)
この授業のゴール
- 文字化けの原因を、文字コード(エンコーディング)の食い違いとして説明できる
- UTF-8とCP932(Shift_JISの拡張)で、同じ日本語が何バイトになるかを確かめられる
- ファイルを開く前に、出所・拡張子・サイズ・先頭バイト・先頭数行の5点を確認できる
- 二重拡張子や実行ファイルの拡張子を見分け、開かない判断ができる
仕事でどう使うか
データの仕事では、他人が作ったファイルを毎日のように開きます。文字化けしたまま分析すると、カテゴリ名が壊れて集計が合いません。出所の分からないファイルを開くと、情報漏えいやウイルス感染の入口になります。
| 路線 | この授業の使いどころ |
|---|---|
| DS(データサイエンティスト) | 取引先や他部署のCSVを読み込む前に、文字コードと列数を確認する。読み間違えた列名や値のまま集計しない |
| ML(機械学習エンジニア) | 学習データのカテゴリ名やテキストが壊れていないか確認する。文字化けしたラベルは、別のクラスとして学習される |
| DX(DX推進・AI企画) | 業務システムの入出力ファイルの文字コード・改行・区切り文字を仕様に書く。ファイル受け渡しの安全ルールを決める |
| RS(研究者) | 共同研究者から受け取るデータの出所と形式を記録する。再現性のために文字コードも記録に残す |
この授業の判定ポイントは、拡張子だけで形式を信じないことと、開く前に確認することです。
前提
前提は、ファイル・フォルダ・拡張子 の拡張子と先頭バイトの考え方、保存・ダウンロード・アップロード の「文字数とバイト数は別の量」です。
- バイト列(
bytes):ファイルの中身そのもの。0〜255の数の並び - 文字列(
str):人間が読む文字の並び。バイト列をある規則で読み解いたもの - CSV(Comma-Separated Values:カンマ区切りの値):1行が1件、列がカンマで区切られたテキスト形式
この授業では、実行ファイルを開く練習はしません。教材のCSV(架空データ)だけを使います。
身近な状況:開いたら「縺ゅ>縺…」だらけ
Fさんは、他部署から届いたCSVを開きました。ところが、列名が 譛磯。� のような記号の羅列になっていました。壊れたのではなく、読み方を間違えているだけです。
もう1つの場面です。Fさんのメールに、請求書.pdf.exe という添付ファイルが届きました。画面の設定で拡張子が非表示なら、請求書.pdf に見えます。
この2つは、どちらも「名前や見た目と、中身の読み方がずれる」という同じ種類の問題です。
| 場面 | 起きていること | 対処 |
|---|---|---|
| 文字化け | ファイルが書かれた文字コードと、読むときの文字コードが違う | 正しい文字コードで読み直す。化けたまま保存しない |
| 二重拡張子 | 最後の拡張子が実行ファイルを示すのに、前の部分でPDFに見せている | 最後の拡張子で判断し、開かない |
この授業では、ファイルを開く前に確認する手順と、開いた後に中身を確かめる手順を身につけます。
直感的な説明:文字と番号の対応表
コンピューターは文字を直接しまえません。文字に番号を振り、その番号をバイト列にして保存します。このとき、どの番号表・どの変換規則を使うかが文字コード(エンコーディング)です。
たとえるなら、暗号の本です。書く人がA社の暗号本で書いた文を、読む人がB社の暗号本で読むと、意味の違う文字になります。バイト列は同じでも、読む規則が違えば別の文字になります。
日本語のCSVでよく出会う規則は2つです。
- UTF-8(ユーティーエフ・エイト):世界中の文字を扱える、現在の標準的な規則。日本語1文字は通常3バイト。
- CP932(Shift_JISにWindows独自の文字を足したもの):日本語の古い規則で、Windows版のExcelなどが出力するCSVにあります。日本語1文字は通常2バイト。
たとえの限界:文字コードは暗号ではなく公開された規則です。ただし、ファイルの中に「この規則で書いた」という印が必ず入っているわけではなく、読む側が推測することが多い点が、問題の原因です。
正確な定義:Unicode、エンコーディング、BOM、改行
Unicode は、世界中の文字に番号(コードポイント)を振った規格です。UTF-8 は、その番号を1〜4バイトで保存する方式(エンコーディング)の1つです。
| 用語 | 意味 |
|---|---|
| エンコード(encode) | 文字列(str)→ バイト列(bytes)。s.encode("utf-8") |
| デコード(decode) | バイト列 → 文字列。b.decode("utf-8")。規則が合わないとエラーか文字化け |
| BOM(Byte Order Mark) | UTF-8ファイルの先頭に付く3バイト EF BB BF。Excelなどが「UTF-8だ」と判断する目印に使う |
| 改行コード | 行の区切り。\n(LF)が主流、Windowsでは \r\n(CRLF)もある |
Pythonでのutf-8-sigは、BOMがあれば除いて読み、なければそのまま読むデコード方式です。
同じ日本語を2つの規則でエンコードし、バイト数を比べます。
s = "こんにちは"
print(len(s))
print(len(s.encode("utf-8")), len(s.encode("cp932")))
b = s.encode("utf-8")
print(b.decode("cp932"))
出力は、5(文字数)、15 10(UTF-8は15バイト、CP932は10バイト)、そして 縺薙s縺ォ縺。縺ッ です。UTF-8で書いたバイト列をCP932で読むと、エラーにならずに文字化けします。エラーが出ない文字化けがあるので、「読めた」だけでは正しさの確認になりません。
段階付き例題:教材CSVを開く前と開いた後に確認する
問題:教材の churn.csv(解約データ。架空)を、安全に確認して読み込む。
ステップ1:出所を確認する。この教材に内蔵された架空データなので、出所は明確です。実務では「誰が・いつ・どの経路で」送ったかを確認し、不明なら開きません。
ステップ2:名前と拡張子。churn.csv は最後の拡張子が csv で、二重拡張子ではありません。ただし、これだけでは形式を保証しません。
ステップ3:サイズ。極端に大きい、または小さいときは疑います。
ステップ4:先頭バイト。BOMの有無、実行ファイルやZIPの目印がないかを確認します。
ステップ5:先頭の数行を読んで、列数をそろえて確認する。
from collections import Counter
raw = open("/data/churn.csv", "rb").read()
print(len(raw), raw[:3] == b"\xef\xbb\xbf")
text = raw.decode("utf-8")
lines = text.splitlines()
print(len(lines))
print(lines[1])
print(Counter(len(l.split(",")) for l in lines))
try:
raw.decode("cp932")
except UnicodeDecodeError as e:
print("cp932では読めない:", type(e).__name__)
出力は、158657 False(バイト数、BOMなし)、3001(ヘッダー1行+3000行)、1,56,2980,0,14.7,月額,東日本,50代以上,,0,train、Counter({11: 3001})(全行が11列)、cp932では読めない: UnicodeDecodeError です。
ステップ6:意味を言葉にする。このファイルはUTF-8として読め、全行の列数が一致します。CP932で読むと、エラーが出ました。どの文字コードで読めたかを記録に残します。なお、行によっては列数が違う場合、カンマを含む値が引用符で囲まれている可能性があるので、pandas.read_csv のような専用の道具で読む場合も、行数と列数の確認は欠かせません。
操作して理解する:読む規則を変えて、結果を見る
次のコードで、日本語を2つの規則で書き、読む規則をそろえた場合・食い違わせた場合を比べます。
word = "売上"
u = word.encode("utf-8")
c = word.encode("cp932")
print(u, c)
def try_decode(b, enc):
try:
return b.decode(enc)
except UnicodeDecodeError:
return "(エラー)"
for name, b in (("UTF-8で書いた", u), ("CP932で書いた", c)):
print(name, try_decode(b, "utf-8"), try_decode(b, "cp932"))
出力は、b'\xe5\xa3\xb2\xe4\xb8\x8a' b'\x94\x84\x8f\xe3'、UTF-8で書いた 売上 (エラー)、CP932で書いた (エラー) 売上 です。1行目のバイト列は左がUTF-8(6バイト)、右がCP932(4バイト)です。
注目点は2つです。(1) 書いた規則で読めば正しく読め、違う規則で読むと、この例ではエラーになります。(2) 前の節の こんにちは は、UTF-8で書いたものをCP932で読んでもエラーにならず文字化けしました。同じ「規則の食い違い」でも、エラーになるかどうかはバイト列の並びで決まります。エラーの有無だけで判断せず、読んだ結果を目で見ることが必要です。
実務では、次の順で試すのが定石です。
utf-8-sig(BOMの有無どちらにも対応)で読む。- 失敗したら
cp932で読む。 - 読めた結果の先頭数行を目で見て、日本語が正しいことを確かめる。
試してみる:word を "こんにちは" や "ABC" に変えて、バイト数と読み方の結果がどう変わるか確かめましょう。半角英数字はUTF-8でもCP932でも1文字1バイトで、同じバイト列になります。
発展:自動判定の限界と、ファイルの危険度
文字コードの自動判定は推定です。バイト列の並びの統計から「たぶんこの規則」と当てるもので、短いファイルや、特定の文字だけのファイルでは外れます。外れたときは、読んだ結果を目で見て気付くしかありません。
拡張子ごとの危険度の目安(一般的な考え方):
| 分類 | 拡張子の例 | 扱い |
|---|---|---|
| データ(テキスト) | .csv、.txt、.json |
実行されない。ただし中身の確認は必要 |
| 文書・表計算 | .pdf、.xlsx、.docx |
通常は安全だが、マクロ入り(.xlsm、.docm)は実行機能を持つ |
| 圧縮 | .zip、.gz |
展開してから、中身の名前と拡張子を確認する |
| 実行ファイル・スクリプト | .exe、.bat、.cmd、.js、.vbs、.scr、.ps1、.msi、.jar |
データとして届いたら開かない |
二重拡張子(請求書.pdf.exe)では、最後の拡張子が実際の種類を決めます。OSの設定で拡張子を表示しておくことが、最初の防御です。
出所が不明、緊急を装う、パスワード付きZIPで届く、といった特徴はよくある手口です。判断に迷うときは、開かずに、情報システム部門などの担当者に相談します。セキュリティの扱いは組織のルールが優先です。この説明は執筆時点(2026年)の一般的なもので、最新は組織や公的機関の案内で確認してください。
CSVの区切り文字・引用符にも例外があります。値にカンマを含む場合、"東京,23区" のように引用符で囲みます。単純な split(",") では列がずれるため、実務では専用の読み込み関数(csv モジュールや pandas)を使います。
よくある失敗
失敗1:化けた文字をそのまま保存し直して、原本を壊す
誤った操作:文字化けしたCSVを、そのまま「保存」した。
original = "売上".encode("utf-8")
garbled = original.decode("cp932", errors="replace")
saved = garbled.encode("utf-8")
print(garbled, saved)
print(saved == original)
出力は 螢イ荳� b'\xe8\x9e\xa2\xef\xbd\xb2\xe8\x8d\xb3\xef\xbf\xbd' と False です。化けた文字を保存すると、元のバイト列に戻せなくなります。特に、errors="replace" で置換した文字(�)は、元の情報が失われます。
直し方:文字化けしたら、保存せず、読み込む文字コードを変えて読み直す。原本は別に残し、作業用コピーで試す(ファイル・フォルダ・拡張子)。
失敗2:拡張子の見た目で、安全なPDFだと思い込む
誤った判断:請求書.pdf.exe が画面で 請求書.pdf に見えたので、PDFだと思って開いた。
from pathlib import PurePosixPath
name = "請求書.pdf.exe"
p = PurePosixPath(name)
print("見かけ:", p.stem)
print("最後の拡張子:", p.suffix)
print(p.suffixes)
出力は 見かけ: 請求書.pdf、最後の拡張子: .exe、['.pdf', '.exe'] です。実際の種類は最後の .exe で、実行ファイルです。
直し方:OSの設定で拡張子を表示し、最後の拡張子で判断する。実行ファイルがデータとして届いたら開かず、担当者に報告する。
失敗3:文字数とバイト数を取り違える
誤った判断:「入力欄の上限は20バイト。メモは9文字だから入る。」
name = "山田太郎の注文メモ"
print(len(name))
print(len(name.encode("utf-8")))
print(len(name.encode("cp932")))
出力は 9(文字数)、27(UTF-8のバイト数)、18(CP932のバイト数)です。上限20バイトに対して、UTF-8では27バイトで入らず、CP932では18バイトで入ります。上限が文字数かバイト数か、どの文字コードのバイトかで、入る・入らないが変わります。
直し方:仕様に「文字数」か「バイト数」かを書く。バイトで数えるなら、文字コードも書く。確認は len(s) と len(s.encode(...)) の両方で行います。
まとめ
- 文字化けは、書いた文字コードと読む文字コードの食い違いで起きる。UTF-8は日本語が通常3バイト、CP932は2バイト。
- エラーが出ない文字化けがある。読んだ結果の先頭数行を目で見て確かめる。化けたまま保存しない。
- ファイルを開く前に、出所・拡張子・サイズ・先頭バイト・先頭数行の5点を確認する。
- 拡張子は最後の
.以降。二重拡張子や実行ファイル・スクリプトの拡張子はデータとして開かない。
用語
- 文字コード(character encoding)
文字を番号とバイト列に対応づける規則。UTF-8やCP932などがある。
- UTF-8(UTF-8)
Unicodeの文字を1〜4バイトで表す標準的な方式。日本語は通常3バイト。
- CP932(CP932 (Windows-31J))
Shift_JISにWindows独自の文字を加えた日本語の文字コード。日本語は通常2バイト。
- BOM(Byte Order Mark)
UTF-8ファイルの先頭に付くことがある3バイトの目印。
utf-8-sigで読むと除かれる。- 二重拡張子(double extension)
請求書.pdf.exeのように拡張子が2つ以上続く名前。実際の種類は最後の拡張子で決まる。
よくある質問
なぜ文字コードが複数あるのですか?
コンピューターの歴史の中で、国や会社ごとに別々の規則が作られたからです。日本語だけでもCP932やEUC-JPなどがあります。現在は世界共通のUnicodeとUTF-8が標準で、新しいシステムの多くはUTF-8を使います。
ExcelでCSVを開くと文字化けするのはなぜですか?
ExcelがBOMのないUTF-8を、CP932として読むことがあるからです。BOM付きUTF-8で保存するか、Excelの「データの取り込み」機能で文字コードを指定すると読めます。環境や版によって動作が異なるので、実際の画面で確認してください。
文字コードを自動判定するライブラリがあれば、確認は不要ですか?
不要にはなりません。自動判定は推定なので、外れることがあります。読んだ結果の先頭数行を目で見て確かめる手順は残します。判定結果が間違っても、気付ける仕組みを持つことが大切です。
CSVの列数が行によって違うのは、何が原因ですか?
値にカンマや改行が含まれ、引用符で囲まれている場合に、単純なsplit(',')で数えると列数がずれて見えます。また、データ自体の欠落や、手作業の編集ミスも原因になります。専用の読み込み関数で読み、行数・列数を確認します。
ウイルス対策ソフトがあれば、開く前の確認は不要ですか?
不要にはなりません。対策ソフトは多くの脅威を検出しますが、全てではありません。出所と拡張子の確認は、自分でできる最初の防御です。ソフトの検査と、人の確認を重ねます。
個人情報を含むCSVを受け取ったときは、どうしますか?
社内のルールに従って保管し、必要な範囲の人だけが見られるようにします。受け取った事実、保存先、削除期限を記録に残します。この教材のデータは全て架空ですが、実務では最初にルールを確認してください。
確認問題
問1 UTF-8で保存されたCSVを、CP932として読むと起こりやすいことはどれか。
- ① 必ずエラーで止まる
- ② エラーにならず文字化けすることも、エラーになることもある
- ③ 自動的に正しい日本語になる
- ④ ファイルが削除される
解答と解説
正解:②
バイト列の並びによって、不正なバイトが出てエラーになる場合と、別の文字として読めて文字化けする場合があります。
問2 「こんにちは」(5文字)をUTF-8とCP932でバイト列にしたときのバイト数の組み合わせは。
- ① UTF-8:5、CP932:5
- ② UTF-8:10、CP932:15
- ③ UTF-8:15、CP932:15
- ④ UTF-8:15、CP932:10
解答と解説
正解:④
UTF-8では日本語1文字が通常3バイト、CP932では2バイトなので、5文字は15バイトと10バイトです。
問3 請求書.pdf.exe というファイルが届いた。この実際の種類として最も適切なのはどれか。
- ① 実行ファイル
- ② PDFファイル
- ③ 文字コードがPDFの画像
- ④ ZIPファイル
解答と解説
正解:①
拡張子は最後の . 以降で決まります。最後の .exe が実際の種類で、PDFに見せかけた実行ファイルの可能性があります。
問4 UTF-8のBOM付きファイルを utf-8(BOMを除かない)で読むと、起こりうることはどれか。
- ① ファイルが読めずエラーになる
- ② 全ての日本語が文字化けする
- ③ 1行目の最初の列名の前に、見えない文字
\ufeffが付く - ④ BOMは読み込みに一切影響しない
解答と解説
正解:③
BOMは先頭の3バイトで、utf-8 で読むとコードポイント \ufeff として残ります。utf-8-sig なら除かれます。
問5 文字化けしたCSVを見つけた。最初にすべきことはどれか。
- ① そのまま上書き保存して、後で直す
- ② 文字を手で打ち直す
- ③ ファイルを削除して作り直す
- ④ 保存せずに、読み込む文字コードを変えて読み直す
解答と解説
正解:④
化けた文字を保存すると、元のバイト列に戻せなくなります。読み方を変えれば、原本は変えずに直せます。
問6 知らない相手から届いたZIPの中に data.csv が入っていた。開く前の対応として最も適切なのはどれか。
- ① CSVはデータなので、そのまま開いてよい
- ② 出所を確認できるまで開かず、必要なら担当者に相談する
- ③ 拡張子を
.xlsxに変えてから開く - ④ ZIPごと別の人に転送する
解答と解説
正解:②
拡張子が .csv でも、中身や出所は保証されません。出所が不明なファイルは、確認が取れるまで開かないのが基本です。
次に学ぶこと
次は エラー時の切り分けとバックアップ で、エラーが出たときの切り分けと、バックアップを学びます。ここまでの確認手順を使って、統合演習(CSVを読み込み、ノートと結果を出力して再読込する)を行います。
この授業の確認問題だけでモジュールの習得とはしません。ON01 の総合テストと、CSVを使った自力課題で判定します。データの1行が何を表すかは 行と列と1行の単位 で扱います。
キャリア学習:データサイエンティスト・機械学習エンジニア・DX推進・研究者を目指す人の学習アプリ。164モジュール・984授業を、ブラウザで動くSQLとPythonの演習で。基礎と各分野の最初のモジュールは無料。全部は2,980円の買い切り。
アプリを無料で開く有料版と無料版の違い