0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

文字はどうやって数字になる?ASCIIコードを10進数・16進数・2進数で理解する

0
Posted at

プログラムを書いていると、

A = 65
a = 97
0 = 48

のような数字を見かけることがあります。

なぜ文字のAが65なのでしょうか。

これはASCIIコードという、文字と数値を対応付ける仕組みによるものです。

普段は文字として見えていても、コンピュータ内部では最終的に数値として扱われています。

この記事では、

  • ASCIIコードとは何か
  • 文字と数値の関係
  • 10進数・16進数・2進数での見え方
  • JavaScriptで文字コードを取得する方法
  • ASCIIを知っていると役立つ場面

を順番に整理します。

ASCIIコードとは?

ASCIIは、

American Standard Code for Information Interchange

の略です。

文字や記号に数値を割り当てた文字コードです。

たとえば、

A → 65
B → 66
C → 67

という対応があります。

小文字では、

a → 97
b → 98
c → 99

です。

数字の文字も、

0 → 48
1 → 49
2 → 50

のようにコードが割り当てられています。

「数字の1」と数値の1は違う

ここはプログラミング初心者が混乱しやすいポイントです。

たとえば、

1

という見た目でも、

数値としての1

と、

文字としての"1"

は別物です。

文字の"1"をASCIIコードで見ると、

49

です。

つまり、

数値 1

と、

文字 "1" → ASCII 49

は同じではありません。

Aが65なのはなぜ?

ASCIIでは大文字のAからZまでが連続して割り当てられています。

A = 65
B = 66
C = 67
...
Z = 90

そのため、

Aから何文字離れているか

を計算することもできます。

たとえばDは、

65 + 3
= 68

なのでASCIIコード68です。

小文字も連続している

小文字も同じです。

a = 97
b = 98
c = 99
...
z = 122

大文字と小文字ではコードが違います。

たとえば、

A = 65
a = 97

です。

差は、

97 - 65
= 32

です。

ASCIIの範囲では、大文字と対応する小文字の間に32の差があります。

数字も連続している

数字の文字は、

0 = 48
1 = 49
2 = 50
3 = 51
...
9 = 57

です。

この連続性を利用すると、文字の数字を数値へ変換する処理を理解しやすくなります。

たとえば文字"7"のASCIIコードは55です。

55 - 48
= 7

なので、'0'のコードを引けば数字としての7が得られます。

Cなどの低レベル寄りのコードでは、この考え方をよく見かけます。

ASCIIは10進数だけではない

ASCIIコードは、

A = 65

のように10進数で説明されることが多いですが、同じ値を16進数や2進数でも表せます。

Aなら、

10進数:65
16進数:41
2進数 :01000001

です。

すべて同じ値です。

表記方法が違うだけです。

なぜ16進数で見ることが多い?

コンピュータ関連では、ASCIIコードを16進数で見ることもよくあります。

たとえば、

A = 0x41
B = 0x42
C = 0x43

です。

数字なら、

0 = 0x30
1 = 0x31
2 = 0x32

です。

16進数は1バイトの値を、

00〜FF

の2桁で表せるため、バイナリデータを見るときに扱いやすいという特徴があります。

「ABC」を16進数で見る

文字列、

ABC

をASCIIコードにすると、

A = 65
B = 66
C = 67

です。

16進数なら、

41 42 43

です。

そのため、HEXダンプなどで、

41 42 43

を見たとき、

ASCIIとして読むとABC

と判断できます。

「Hello」はどうなる?

HelloをASCIIコードで見ると、

H = 72
e = 101
l = 108
l = 108
o = 111

です。

16進数なら、

48 65 6C 6C 6F

です。

バイナリエディタや通信データを見ていると、このような値を目にすることがあります。

スペースにもコードがある

文字だけではなく、スペースにもコードがあります。

半角スペースは、

10進数:32
16進数:20

です。

たとえば、

Hello World

のHelloとWorldの間にも、ASCIIコード32の文字が入っています。

画面では何も見えませんが、データとしては存在しています。

改行にもコードがある

改行などの制御文字にも数値が割り当てられています。

代表的なのが、

LF = 10
CR = 13

です。

16進数なら、

LF = 0A
CR = 0D

です。

Windowsのテキストでは、

CR + LF

つまり、

0D 0A

が改行として使われることがあります。

Unix系では、

LF

のみが使われることが一般的です。

改行コードの違いもASCIIにつながる

Gitなどで、

LF
CRLF

という言葉を見たことがあるかもしれません。

これもASCIIの制御文字と関係しています。

LF
= Line Feed
= 10
= 0x0A
CR
= Carriage Return
= 13
= 0x0D

という対応です。

ASCIIを知ると、改行コードの話も理解しやすくなります。

TABも文字コードとして存在する

タブ文字もASCIIに含まれます。

TAB = 9

16進数なら、

09

です。

見た目では複数の空白のように見えますが、

スペースを何個も並べている

わけではありません。

一つの制御文字です。

ASCIIの範囲は?

標準ASCIIは7bitで表現されます。

7bitで表現できる値は、

0〜127

です。

つまり全部で、

128種類

です。

この中には、

英大文字
英小文字
数字
記号
制御文字

などが含まれています。

なぜ7bitなの?

7bitなら、

2^7 = 128

通りの値を表現できます。

初期のコンピュータ通信では、英数字や基本的な記号を扱うためにこの範囲が使われました。

現在のコンピュータでは8bit=1byteが基本ですが、ASCII自体は7bitの文字コードです。

0〜31は何?

ASCIIコードの、

0〜31

には主に制御文字が割り当てられています。

たとえば、

TAB
LF
CR
ESC

などです。

普通の文字のように画面へ表示するためではなく、通信やテキスト制御などに使われてきました。

表示できるASCII文字

一般的に画面へ表示される文字は、

32〜126

あたりです。

32はスペース。

33以降には、

!
"
#
$
%

などの記号が並びます。

さらに、

数字
大文字
小文字

が続きます。

JavaScriptでASCIIコードを取得する

JavaScriptでは、

const code = "A".charCodeAt(0);

console.log(code);
// 65

とすると、文字コードを取得できます。

Bなら、

console.log("B".charCodeAt(0));
// 66

です。

数値から文字へ戻す

逆に、

String.fromCharCode()

を使えば、コードから文字を作れます。

console.log(
  String.fromCharCode(65)
);
// A

複数指定することもできます。

console.log(
  String.fromCharCode(72, 101, 108, 108, 111)
);
// Hello

です。

文字列全体をコードへ変換する

たとえば、

const text = "Hello";

const codes = [...text].map(
  char => char.charCodeAt(0)
);

console.log(codes);

結果は、

[72, 101, 108, 108, 111]

です。

ASCII文字だけなら、このように文字とコードの関係を見ることができます。

16進数に変換する

JavaScriptでASCIIコードを16進数表示したい場合は、

const hex = "A"
  .charCodeAt(0)
  .toString(16);

console.log(hex);
// 41

です。

文字列なら、

const text = "Hello";

const hex = [...text]
  .map(char =>
    char
      .charCodeAt(0)
      .toString(16)
      .padStart(2, "0")
  )
  .join(" ");

console.log(hex);
// 48 65 6c 6c 6f

とできます。

ASCIIコードをすぐ確認したい場合

文字から10進数・16進数などの値を確認したり、逆に数値から対応する文字を調べたい場合は、ASCIIコードを確認すると、対応関係を見比べやすくなります。

特にバイナリやHEXの値を見ていて、

この値は文字にすると何?

と確認したいときに便利です。

ASCIIとUnicodeは同じ?

同じではありません。

ASCIIで扱えるのは、基本的に英数字や一部記号などです。

たとえば、

A
Z
1
?

などはASCIIにあります。

一方、

あ
漢
😀

のような文字はASCIIだけでは表現できません。

現在はUnicodeという、はるかに多くの文字を扱える仕組みが広く使われています。

ASCIIはUnicodeの中にも残っている

ASCIIが古いから完全に使われなくなった、というわけではありません。

Unicodeでは、ASCIIの基本的な文字について同じコードポイントが維持されています。

たとえば、

A

はUnicodeでも、

U+0041

です。

これはASCIIの16進数、

0x41

と一致します。

そのため、ASCIIは現在の文字コードを理解するうえでも重要です。

ASCIIとUTF-8の関係

現在のWebではUTF-8が非常によく使われています。

UTF-8では、ASCII範囲の文字は1byteで表現され、値もASCIIと同じです。

たとえば、

A

なら、

41

です。

Helloなら、

48 65 6C 6C 6F

です。

ASCIIだけで構成されたテキストは、UTF-8でも同じバイト列になります。

日本語になると違う

たとえば、

あ

はASCIIにはありません。

UTF-8では複数バイトで表現されます。

この違いを知っていると、

ASCII文字は1文字1byteなのに
日本語ではバイト数が増える

理由も理解しやすくなります。

文字数とバイト数は同じとは限らない

ASCII文字だけなら、

Hello

は5文字で、UTF-8では5byteです。

しかし日本語を含むと、

文字数
バイト数

は一致しない場合があります。

このため、

データベース
API
ファイルサイズ
入力文字数制限

などでは、文字数とバイト数を区別する必要があります。

HTTPでもASCIIを見ることがある

HTTPなどの通信プロトコルでは、

GET
POST
Host
Content-Type

のような英数字が多く使われます。

通信内容をHEXダンプで確認すると、それらの文字もASCII値として見えます。

たとえば、

GET

なら、

47 45 54

です。

ASCIIを理解していると、通信データを低レベルで読むときにも役立ちます。

HEXダンプでASCII表示が付いている理由

バイナリエディタやHEXビューアでは、

左側に16進数
右側に文字

という表示をよく見かけます。

たとえば、

48 65 6C 6C 6F    Hello

のような表示です。

これはバイト値をASCII文字として解釈して表示しています。

人間にとって、

48 65 6C 6C 6F

だけを見るより、

Hello

と表示された方が内容を判断しやすいためです。

デバッグでも役立つ

たとえば入力値の中に、

見えないスペース
改行
TAB

が混ざっているとします。

画面だけでは原因が分からないことがあります。

しかし文字コードを見ると、

32
10
9

などが確認できます。

すると、

32 → SPACE
10 → LF
9 → TAB

と原因を特定できます。

全角スペースと半角スペースの違い

半角スペースはASCIIにあり、

32

です。

しかし全角スペースはASCIIではありません。

見た目はどちらも空白ですが、内部的には別の文字です。

入力チェックや文字列比較で、

見た目は同じなのに一致しない

という問題が起こる理由の一つです。

大文字・小文字判定にも利用できる

ASCIIでは、

A〜Z = 65〜90
a〜z = 97〜122

と連続しています。

そのため理論上は、

const code = "G".charCodeAt(0);

if (code >= 65 && code <= 90) {
  console.log("英大文字");
}

のような判定もできます。

数字なら、

if (code >= 48 && code <= 57) {
  console.log("数字");
}

です。

実際のアプリケーションではUnicodeも考慮する必要がありますが、ASCIIの構造を理解する例として分かりやすい処理です。

32を足せば常に小文字になる?

ASCIIの英字だけを考えると、

A = 65
a = 97

なので、

65 + 32 = 97

です。

Bとb、Cとcも同じです。

そのためASCIIレベルでは、大文字から小文字への変換をビットや数値演算で説明できます。

ただし、実際の文字列処理では、

toLowerCase()

などを使う方が適切です。

世界中の文字がASCIIと同じ規則で動くわけではありません。

ASCIIを丸暗記する必要はない

すべてのコードを覚える必要はありません。

まず覚えておくと便利なのは、

0 = 48
A = 65
a = 97
SPACE = 32
LF = 10
CR = 13

くらいです。

あとは必要なときに確認すれば十分です。

重要なのは、

文字も内部では数値として表現されている

という考え方を理解することです。

まとめ

ASCIIは、英数字や記号などに数値を割り当てた文字コードです。

代表的な値は、

A = 65 = 0x41
a = 97 = 0x61
0 = 48 = 0x30
SPACE = 32 = 0x20

です。

同じ値でも、

10進数
16進数
2進数

で表現できます。

ASCIIを理解すると、

  • HEXダンプ
  • バイナリデータ
  • 改行コード
  • 通信データ
  • 文字列処理
  • UTF-8との関係

なども理解しやすくなります。

最初は、

「Aが65なのを覚える」

ことより、

画面に見えている文字にも、コンピュータ内部では対応する数値がある

と理解するところから始めると分かりやすいでしょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?