ASCII가 무엇이고 왜 중요할까?

ASCII가 무엇이고 왜 중요할까?

컴퓨터로 텍스트를 다루다 보면 “ASCII 코드”라는 용어를 종종 마주치게 됩니다. URL 인코딩을 설명할 때나 한글이 깨지는 문제를 디버깅할 때마다 ASCII가 빠지지 않고 등장하는데요.

이번 포스팅에서는 ASCII가 무엇이고 왜 만들어졌는지부터 짚어보겠습니다. 문자표가 어떻게 구성되어 있는지, 오늘날 UTF-8과는 어떤 관계를 가지는지도 함께 살펴보겠습니다.

ASCII란?

ASCII는 American Standard Code for Information Interchange의 약자로, 영문자와 숫자, 그리고 일부 특수 문자를 0부터 127까지의 정수로 매핑한 문자 인코딩 표준입니다.

쉽게 말해 “A는 65번, B는 66번, 0은 48번…”처럼 각 글자에 고유한 번호를 부여한 약속인데요.

컴퓨터는 본질적으로 0과 1만 다룰 수 있는 기계라서 사람이 쓰는 글자를 직접 처리하지 못합니다. 그래서 글자마다 숫자를 매겨두고 그 숫자를 컴퓨터가 다루도록 한 것이 바로 ASCII의 핵심 아이디어입니다.

A   = 65 = 0x41 = 01000001
B   = 66 = 0x42 = 01000010
0   = 48 = 0x30 = 00110000
공백 = 32 = 0x20 = 00100000

ASCII는 7비트로 표현되기 때문에 총 2의 7제곱, 즉 128가지의 문자만 표현할 수 있습니다.

ASCII가 등장한 배경

ASCII는 1963년에 미국 표준 협회(ANSI)에서 처음 제정되었습니다. 그 이전에는 컴퓨터 제조사마다 자체적으로 문자 인코딩을 만들어 썼는데요. IBM이 사용하던 EBCDIC을 비롯해 여러 회사의 다양한 표준이 난립해서 컴퓨터끼리 데이터를 주고받기가 무척 어려운 상황이었습니다.

이런 혼란을 해결하기 위해 통일된 표준이 필요했고, 그렇게 등장한 것이 바로 ASCII입니다. ASCII가 널리 채택되면서 서로 다른 컴퓨터 사이에서도 텍스트 데이터를 주고받을 수 있게 되었고, 이는 훗날 인터넷 시대의 토대가 되었습니다.

ASCII 문자표의 구성

ASCII의 128개 코드는 크게 두 부분으로 나뉘는데요.

먼저 0번부터 31번까지, 그리고 127번은 제어 문자(control character)입니다. 이들은 화면에 표시되는 글자가 아니라 프린터나 터미널에 명령을 내리기 위한 신호입니다.

0   = NUL (널 문자)
9   = TAB (탭)
10  = LF  (줄 바꿈, line feed)
13  = CR  (캐리지 리턴, carriage return)
27  = ESC (이스케이프)
127 = DEL (삭제)

다음으로 32번부터 126번까지는 출력 가능한 문자(printable character)입니다. 우리가 키보드에서 직접 입력하는 거의 모든 문자가 여기에 속합니다.

32       = 공백
48-57    = 0-9 (숫자)
65-90    = A-Z (영문 대문자)
97-122   = a-z (영문 소문자)
33-47    = ! " # $ % & ' ( ) * + , - . /
58-64    = : ; < = > ? @
91-96    = [ \ ] ^ _ `
123-126  = { | } ~

여기서 한 가지 흥미로운 점은 영문 대문자 A부터 Z까지가 65~90이고, 소문자 a부터 z까지가 97~122라는 사실입니다. 두 범위의 차이가 정확히 32, 즉 0x20이라서 비트 연산만으로도 대소문자를 빠르게 변환할 수 있습니다.

Latin-1과 EUC-KR

ASCII의 가장 큰 한계는 영어 외의 언어를 표현하지 못한다는 점입니다. 한글, 한자, 일본어, 아랍어, 그리스어 같은 다양한 언어의 문자는 ASCII 128개 안에 도저히 들어갈 수 없는데요.

이런 한계를 1바이트(8비트) 안에서 보완하기 위해 다양한 확장 인코딩이 등장했습니다. 가장 대표적인 두 가지가 서유럽을 위한 Latin-1과 한국을 위한 EUC-KR입니다.

Latin-1(공식 명칭 ISO 8859-1)은 ASCII가 사용하지 않던 128~255 영역을 활용해서 서유럽 언어의 문자를 추가한 인코딩입니다.

0   ~ 127  : ASCII (영문, 숫자, 기본 기호)
128 ~ 255  : Latin-1 확장 (é, ñ, ü, ö, £, ¥ 등)

영어뿐 아니라 프랑스어, 독일어, 스페인어 같은 서유럽 언어를 1바이트 안에서 표현할 수 있게 된 거죠. 한 글자가 정확히 1바이트라는 단순함 덕분에 1990년대 웹의 사실상 표준으로 자리잡았고, 지금도 HTTP 헤더 같은 일부 영역에 그 흔적이 남아 있습니다.

반면 한국이나 일본처럼 한자권 언어를 쓰는 곳에서는 1바이트(256가지)로는 도저히 모든 글자를 담을 수 없는데요. 그래서 한국에서는 EUC-KR이라는 2바이트 인코딩을 만들어 썼습니다. ASCII 문자는 1바이트 그대로 두고, 한글이 등장하면 2바이트로 확장해 표현하는 방식입니다.

ASCII 문자 → 1바이트 (예: "A" = 0x41)
한글       → 2바이트 (예: "한" = 0xC7 0xD1)

EUC-KR은 흔히 쓰는 한글 음절과 한자 등을 담아 한국어 컴퓨팅의 토대가 되었습니다. 일본의 Shift_JIS, 중국의 GB2312도 비슷한 발상의 지역별 인코딩입니다.

이런 1바이트나 2바이트 확장 인코딩은 각자의 언어권에서는 잘 동작했지만 한 문서에 여러 언어를 함께 담을 수 없었고, 인코딩 정보가 어긋나면 글자가 깨지는 고질적 문제가 있었습니다.

유니코드와 UTF-8

이런 한계를 통째로 극복하기 위해 등장한 것이 바로 유니코드(Unicode)입니다. 유니코드는 전 세계 모든 문자를 하나의 표에 담는 것을 목표로 한 표준이며, 가장 널리 쓰이는 구현 방식이 UTF-8입니다.

UTF-8의 멋진 점은 ASCII와 완벽하게 호환된다는 사실인데요. ASCII 문자(0~127)는 UTF-8에서도 1바이트로 그대로 표현되고, 한글이나 다른 문자는 2~4바이트로 확장해서 표현됩니다.

A   (U+0041, 65)     → 1바이트: 0x41
한  (U+D55C, 54620)  → 3바이트: 0xED 0x95 0x9C
🚀  (U+1F680, 128640) → 4바이트: 0xF0 0x9F 0x9A 0x80

이런 호환성 덕분에 영어 텍스트만 있는 문서는 ASCII로 해석하든 UTF-8로 해석하든 동일한 결과가 나옵니다. 이것이 오늘날 UTF-8이 사실상 표준 자리를 차지한 가장 큰 이유 중 하나입니다.

자바스크립트에서 ASCII 다루기

자바스크립트에는 문자열의 ASCII 코드를 쉽게 확인하고 변환할 수 있는 메서드가 내장되어 있습니다.

먼저 문자에서 ASCII 코드를 얻으려면 charCodeAt() 메서드를 사용하는데요.

const code = "A".charCodeAt(0);
console.log(code); // 65

반대로 ASCII 코드에서 문자를 얻으려면 String.fromCharCode() 메서드를 사용합니다.

const char = String.fromCharCode(65);
console.log(char); // 'A'

이를 활용하면 영문 알파벳을 순회하거나 대소문자를 변환하는 작업을 간단하게 할 수 있습니다.

// A부터 Z까지 출력
for (let i = 65; i <= 90; i++) {
  console.log(String.fromCharCode(i));
}

// 소문자를 대문자로 변환 (32만큼 빼기)
const upper = String.fromCharCode("a".charCodeAt(0) - 32);
console.log(upper); // 'A'

다만 한글이나 이모지처럼 ASCII 범위를 벗어나는 문자는 charCodeAt()이 유니코드 코드 포인트의 일부만 반환할 수 있어서 주의가 필요한데요. 이런 경우에는 codePointAt()String.fromCodePoint()를 사용하는 것이 안전합니다.

console.log("🚀".charCodeAt(0)); // 55357 (서로게이트 페어의 일부)
console.log("🚀".codePointAt(0)); // 128640 (정확한 유니코드 값)

마치며

지금까지 ASCII가 어떤 배경에서 등장했는지부터 시작해서 문자표 구성과 UTF-8과의 관계까지 두루 살펴보았습니다.

ASCII는 단순한 문자 인코딩을 넘어 컴퓨터가 텍스트를 다루는 모든 방식의 출발점이라 할 수 있는데요. URL 인코딩이나 NanoID 같은 식별자 생성, 심지어 깨진 한글을 디버깅하는 일까지도 결국 ASCII의 원리를 이해하면 한결 명확하게 풀어낼 수 있습니다.

더 자세한 ASCII 명세는 RFC 20을 참고하세요.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord