はじめに: 文字コードは「文字を数値にする約束」
前の記事では、コンピュータが2進数を使う理由を見ました。コンピュータは、電気的に扱いやすいオンとオフの状態をもとに、情報をビット列として表します。
では、私たちが画面で読んでいる「あ」「A」「1」のような文字は、コンピュータの中でどのように扱われているのでしょうか。
結論から言うと、文字そのものがそのまま保存されているわけではありません。コンピュータは、文字に対応する数値を扱っています。「この文字はこの番号にする」という対応関係を決める約束が、文字コードです。
基本情報技術者試験でも、ASCII、Unicode、UTF-8、ビット、バイトといった言葉が出てきます。これらを別々に暗記するより、「文字を数値として扱う仕組み」と考えると整理しやすくなります。この記事では、JavaScriptを使って、文字の番号やUTF-8のバイト列を確認していきます。
文字コードは、文字をコンピュータが扱える数値に対応づけるための約束です。
文字はそのまま保存されているわけではない
私たちは、ブラウザに A と表示されていれば英字のAとして読み、あ と表示されていれば日本語のひらがなとして読みます。しかし、コンピュータ内部では、文字の形そのものを直接保存しているわけではありません。
保存や通信の段階では、文字は数値の並びとして扱われます。その数値をもとに、フォントや表示処理によって画面上の文字の形が描かれます。
たとえば、英字の A にも、日本語の あ にも、文字コード上の番号があります。書き込む側と読む側が同じ約束を使っていれば、同じ文字として解釈できます。反対に、その約束がずれると、あとで出てくる文字化けにつながります。
コンピュータは文字の見た目ではなく、文字に対応する数値を保存・送信しています。
ASCII、Unicode、UTF-8の役割を分けて考える
文字コードを学ぶときに混乱しやすいのが、ASCII、Unicode、UTF-8の違いです。どれも文字に関係しますが、役割が少しずつ違います。
ASCIIは、英数字や基本的な記号を扱うための古くからある文字コードです。たとえば、英字の A、数字の 1、記号の ! などに番号が割り当てられています。英語中心の小さな範囲を扱うには十分でした。
一方で、世界には日本語、中国語、韓国語、絵文字など、非常に多くの文字があります。そこで、世界中の文字をまとめて扱うためにUnicodeが使われます。Unicodeでは、多くの文字に一意の番号が割り当てられます。この番号をコードポイントと呼ぶことがあります。
UTF-8は、Unicodeの番号を実際に保存や通信で使うバイト列として表す方式です。ざっくり言えば、Unicodeは「文字に番号を付ける大きな表」、UTF-8は「その番号をバイト列にする方法」です。
Unicodeは文字に番号を割り当て、UTF-8はその番号をバイト列として表す方式です。
JavaScriptで文字の番号を見てみる
JavaScriptでは、文字に対応する番号を確認できます。ここでは codePointAt() を使って、文字のUnicodeコードポイントを見てみます。
const chars = ["A", "あ", "字"];
for (const char of chars) {
const codePoint = char.codePointAt(0);
console.log(char, codePoint, codePoint.toString(16));
}codePointAt(0) は、文字のコードポイントを取得します。toString(16) は、その数値を16進数で表示するためのものです。文字コードの説明では、コードポイントを U+0041 のように16進数で書くことがよくあります。
たとえば A は U+0041、あ は U+3042 と表せます。見た目は文字ですが、コードから見ると番号として扱えることが分かります。
似たメソッドに charCodeAt() もあります。これはJavaScriptの内部表現であるUTF-16のコード単位を返します。基本的な文字では近い結果に見えますが、絵文字など一部の文字では違いが出ます。Unicodeの番号を見たいときは、まず codePointAt() を使うと考えておくとよいでしょう。
JavaScriptでは、文字に対応する番号をコードから確認できます。
UTF-8では文字ごとに必要なバイト数が変わる
文字コードで実務につながりやすいのが、文字数とバイト数は同じではないという点です。画面上では1文字に見えても、保存や通信では複数バイトになることがあります。
JavaScriptでは、TextEncoder を使うと、文字列をUTF-8のバイト列として確認できます。
const encoder = new TextEncoder();
for (const text of ["A", "あ", "ABC", "こんにちは"]) {
const bytes = encoder.encode(text);
console.log(text, bytes.length, [...bytes]);
}TextEncoder は、文字列をUTF-8のバイト列に変換します。bytes.length を見ると、その文字列がUTF-8で何バイトになるかが分かります。[...bytes] とすると、各バイトの数値も確認できます。
英字の A はUTF-8では1バイトです。一方、日本語の あ は多くの場合3バイトとして表されます。つまり、文字数が1でも、データ量としては1バイトとは限りません。
この違いは、ファイルサイズ、通信量、データベースのカラムサイズ、APIで送るJSONのサイズなどに関係します。Web開発では「見た目の文字数」と「実際のデータ量」がずれる場面がある、という感覚を持っておくと役立ちます。
UTF-8では、見た目の1文字でも、文字によって必要なバイト数が変わります。
文字化けは「読む約束」がずれたときに起きる
文字コードの話でよく出てくるのが、文字化けです。文字化けは、コンピュータが壊れたから起きる不思議な現象ではありません。多くの場合、文字データを作ったときの約束と、読むときの約束がずれたときに起こります。
たとえば、ある文字列をUTF-8として保存したのに、別のエンコーディングとして読もうとすると、同じバイト列でも解釈が変わります。その結果、本来とは違う文字が表示されます。
Webページでは、HTMLの meta charset やHTTPレスポンスヘッダーの Content-Type が関係します。HTMLでは、次のように文字エンコーディングを指定します。
<meta charset="UTF-8">これは、ブラウザに「このHTMLはUTF-8として読んでください」と伝える指定です。現在のWeb開発ではUTF-8を使う場面が多いため、HTML、サーバー、データベース、エディタの設定がそろっているかを見ることが大切です。
文字化けは、文字データを作ったときの約束と読むときの約束がずれたときに起こります。
試験ではどう問われるか
基本情報技術者試験では、文字コードは情報表現の一部として出てきます。ASCII、Unicode、UTF-8といった用語だけでなく、ビットやバイト、データ量の考え方と合わせて問われることがあります。
たとえば、ある文字を表すのに何ビット、何バイト必要か、文字コードの種類によって扱える文字の範囲がどう違うか、といった見方です。ここでは、文字を「人間が読む記号」としてだけでなく、「コンピュータが扱う数値」として見ることが重要です。
ASCIIは扱える範囲が小さい一方、Unicodeは多くの言語や記号を扱うための仕組みです。UTF-8はUnicodeをWebで扱うときによく使われるエンコーディングです。この関係を押さえておくと、用語問題にも対応しやすくなります。
基本情報では、文字コードをビットやバイトによる情報表現の一部として理解することが大切です。
実務ではどう使われるか
Webエンジニアにとって、文字コードはかなり実務寄りの知識です。普段は強く意識しなくても、問題が起きたときに理解が必要になります。
HTMLでは meta charset、HTTPでは Content-Type、データベースでは文字セットや照合順序、APIではJSONの扱いなど、さまざまな場所で文字コードが関係します。どこか一箇所だけ設定がずれていると、画面表示や保存データで文字化けが起きることがあります。
また、ユーザー入力を扱うときにも、文字数とバイト数の違いが関係します。問い合わせフォーム、CSV出力、ファイル名、SNSの投稿などでは、日本語や絵文字を含むデータを扱うことがあります。
現代のWeb開発ではUTF-8にそろえることが多いですが、「UTF-8だから何も考えなくてよい」というわけではありません。どの層でどのエンコーディングとして扱われているかを確認できることが、トラブル調査の助けになります。
Web開発では、HTML、HTTP、データベース、APIの間で文字コードの扱いをそろえることが重要です。
まとめ: 文字コードはビット列と人間の文字をつなぐ橋
文字コードは、文字をコンピュータが扱える数値に対応づけるための約束です。私たちが画面で見ている文字も、保存や通信の段階では数値やバイト列として扱われています。
ASCIIは英数字や基本的な記号を扱う古くからの文字コードです。Unicodeは世界中の文字に番号を割り当てる仕組みで、UTF-8はその番号をバイト列として表す方式です。この役割を分けて考えると、文字コードの話は整理しやすくなります。
JavaScriptでは、codePointAt() で文字の番号を見たり、TextEncoder でUTF-8のバイト列を確認したりできます。実際にコードで見ると、文字が数値やバイト列として扱われていることが実感しやすくなります。
文字コードを理解すると、文字化け、ファイルサイズ、通信量、データベースの設定などがつながって見えてきます。次の記事では、この流れを受けて、データ容量の考え方をJavaScriptで確認していきます。
文字コードを理解すると、人間が読む文字とコンピュータが扱うビット列のつながりが見えてきます。

コメント