- リンクを取得
- ×
- メール
- 他のアプリ
はじめに
農学部卒の私がWebシステム開発会社に入社した当初、文字化けの原因がまったく理解できませんでした。しかし、PHPで実際に文字を出力してみたことで、「文字化けする理由はこういうことか!」と初めて理解できました。文字コードの仕組みを理解していると役立つことが多いので、この記事でその仕組みについて説明します。
パソコンが文字を表示する仕組み
パソコンは0と1の二進数しか扱うことができません。しかし、どうやってこれらの二進数が文字に変換されているのでしょうか?
答えは、文字に数字を割り振り、その数字に対応する文字を表示するという仕組みです。この数字を振り分けた表を「文字コード表」と呼びます。その中で最も基本的な文字コード表が「ASCIIコード表」です。例えば、ASCIIコード表では「a」という文字は65番目の数字が割り振られています。
具体的にディスプレイに文字が表示されるまでの流れは以下の通りです:
- 二進数「00100001」が数値の「65」として解釈されます。
- その数字がASCIIコード表と照合され、「a」という文字が表示されることになります。
しかし、パソコンは数字しか理解できないため、実際に文字を表示する際には「フォント」という文字情報が必要です。フォントにはGID/CIDというIDが割り振られており、このIDと文字コードをマッピングしたものを「CMap」と呼びます。たとえば、明朝体でASCIIコードのデータ「00100001」を表示する場合は、以下のような流れになります:
- 「00100001」 → 65 → ASCIIコード変換用のCMapを参照 → 明朝体のGID/CIDを抽出 → 明朝体の「a」が表示される
参考サイト
文字を出力してみる
次に、UTF-8で文字を出力するPHPプログラムをブラウザで表示してみましょう。
まず、utf8.php
というファイルを作成し、以下のコードを入力します
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<table>
<?php
// 1バイト文字出力(ASCIIコード)
$i = 0;
print '<tr><td></td><td></td>';
while ($i < 16) {
print '<th>' . $i . '</th>';
$i++;
}
print '</tr>';
$oneByte = 0;
$num = 0;
while ($oneByte < 128) {
if (bcmod($num, 16) == 0) {
print '<tr><th>' . dechex($num) . '</th><th>' . $num . '</th>';
}
echo '<td>' . chr($oneByte) . ' </td>';
if (bcmod($num, 16) == 15) {
print '</tr>';
}
$oneByte++;
$num++;
}
// 2バイト文字出力
$twoByte = 194;
while ($twoByte < 224) {
$twoByte2 = 128;
while ($twoByte2 < 192) {
if (bcmod($num, 16) == 0) {
print '<tr><th>' . dechex($num) . '</th><th>' . $num . '</th>';
}
echo '<td>' . chr($twoByte) . chr($twoByte2) . ' </td>';
if (bcmod($num, 16) == 15) {
print '</tr>';
}
$twoByte2++;
$num++;
}
$twoByte++;
}
// 3バイト文字出力
$threeByte = 224;
while ($threeByte < 240) {
$threeByte2 = ($threeByte == 224) ? 160 : 128;
while ($threeByte2 < 192) {
$threeByte3 = 128;
while ($threeByte3 < 192) {
if (bcmod($num, 16) == 0) {
print '<tr><th>' . dechex($num) . '</th><th>' . $num . '</th>';
}
echo '<td>' . chr($threeByte) . chr($threeByte2) . chr($threeByte3) . ' </td>';
if (bcmod($num, 16) == 15) {
print '</tr>';
}
$threeByte3++;
$num++;
}
$threeByte2++;
}
$threeByte++;
}
?>
</table>
</body>
</html>
<head>
<meta charset="utf-8">
</head>
<body>
<table>
<?php
// 1バイト文字出力(ASCIIコード)
$i = 0;
print '<tr><td></td><td></td>';
while ($i < 16) {
print '<th>' . $i . '</th>';
$i++;
}
print '</tr>';
$oneByte = 0;
$num = 0;
while ($oneByte < 128) {
if (bcmod($num, 16) == 0) {
print '<tr><th>' . dechex($num) . '</th><th>' . $num . '</th>';
}
echo '<td>' . chr($oneByte) . ' </td>';
if (bcmod($num, 16) == 15) {
print '</tr>';
}
$oneByte++;
$num++;
}
// 2バイト文字出力
$twoByte = 194;
while ($twoByte < 224) {
$twoByte2 = 128;
while ($twoByte2 < 192) {
if (bcmod($num, 16) == 0) {
print '<tr><th>' . dechex($num) . '</th><th>' . $num . '</th>';
}
echo '<td>' . chr($twoByte) . chr($twoByte2) . ' </td>';
if (bcmod($num, 16) == 15) {
print '</tr>';
}
$twoByte2++;
$num++;
}
$twoByte++;
}
// 3バイト文字出力
$threeByte = 224;
while ($threeByte < 240) {
$threeByte2 = ($threeByte == 224) ? 160 : 128;
while ($threeByte2 < 192) {
$threeByte3 = 128;
while ($threeByte3 < 192) {
if (bcmod($num, 16) == 0) {
print '<tr><th>' . dechex($num) . '</th><th>' . $num . '</th>';
}
echo '<td>' . chr($threeByte) . chr($threeByte2) . chr($threeByte3) . ' </td>';
if (bcmod($num, 16) == 15) {
print '</tr>';
}
$threeByte3++;
$num++;
}
$threeByte2++;
}
$threeByte++;
}
?>
</table>
</body>
</html>
このプログラムでは、
chr
関数を使って数値から1バイトの文字列を出力しています。2バイト、3バイトの文字は関数をつなげることで出力可能です。2バイト目、3バイト目の仕様については、以下のサイトを参考にしてください。