문자에 인코딩이 필요한 이유
컴퓨터는 모든 것을 숫자로 저장합니다. 키보드에서 "A"를 입력하면 컴퓨터는 글자의 모양이 아니라 그 글자를 나타내는 숫자를 저장합니다. 문자를 숫자에 대응시키는 체계가 바로 문자 인코딩입니다. 이 대응이 어긋나면 깨진 글자, 악센트 자리에 물음표, 혹은 설정 잘못된 웹사이트의 상징과도 같은 다이아몬드 속 물음표 기호를 만나게 됩니다.
한 프로그램에서 다른 프로그램으로 텍스트를 붙여넣었더니 특수문자가 의미 불명의 기호로 변한 경험이 있다면, 인코딩 불일치를 직접 겪은 겁니다. 기본 원리를 알면 이런 문제를 예방하고, 발생했을 때 빠르게 해결할 수 있습니다.
ASCII: 모든 것의 시작
ASCII(American Standard Code for Information Interchange)는 1963년에 공개되었습니다. 0부터 127까지의 숫자에 128개의 문자를 배정합니다. 영문 대소문자, 숫자 0~9, 구두점, 그리고 탭·줄바꿈·캐리지 리턴 같은 제어 문자가 포함됩니다.
ASCII는 단순함 속에 우아함이 있었습니다. 7비트면 모든 문자를 표현할 수 있었고, 영어 텍스트에는 완벽했습니다. 하지만 세계에는 128개보다 훨씬 많은 문자가 있습니다. 프랑스어, 독일어, 스페인어에는 악센트 문자가 필요하고, 중국어·일본어·한국어는 수천 개의 고유한 글자를 사용합니다. 아랍어와 히브리어는 오른쪽에서 왼쪽으로 씁니다. ASCII에는 이 모든 것을 담을 여유가 없었습니다.
코드 페이지 시대
ASCII를 넘어서는 문자를 다루기 위해 각 벤더는 코드 페이지라는 확장 문자 집합을 만들었습니다. 8번째 비트(128~255)를 활용해 128개의 문자를 더 추가하는 방식입니다. ISO 8859-1(Latin-1)은 서유럽 언어를, ISO 8859-5는 키릴 문자를, Shift_JIS와 EUC-JP는 일본어를 담당했습니다. 윈도우에는 Windows-1252 같은 자체 변형이 있었습니다.
코드 페이지의 근본적인 문제는 같은 바이트 값이 인코딩에 따라 다른 문자를 뜻한다는 점이었습니다. 0xC0이 Latin-1에서는 "그레이브 악센트가 붙은 A"이지만, 키릴 인코딩에서는 전혀 다른 문자입니다. 어떤 코드 페이지가 사용되었는지 모르고 파일을 열면 모지바케(문자 깨짐)가 발생합니다.
이것은 사소한 불편이 아니었습니다. 국제 커뮤니케이션, 데이터 교환, 소프트웨어 개발에 실질적인 장벽을 만들었습니다.
유니코드: 모든 문자에 하나의 번호
유니코드 컨소시엄은 이 문제를 영구적으로 해결하기 위해, 모든 문자 체계의 모든 문자에 고유한 번호 — 코드 포인트 — 를 부여하기로 했습니다. 1991년 첫 버전은 약 7,000자를 다뤘고, 현재 유니코드 15.1은 161개 스크립트에 걸쳐 149,000자 이상과 수천 개의 기호, 이모지를 정의합니다.
유니코드 코드 포인트는 U+XXXX 형식으로 표기합니다. U+0041은 라틴 대문자 A, U+AC00은 한글 "가", U+1F600은 활짝 웃는 이모지입니다. 플랫폼이나 애플리케이션에 관계없이 모든 문자에 정확히 하나의 코드 포인트가 대응됩니다.
하지만 유니코드는 문자 집합이지, 인코딩이 아닙니다. 어떤 숫자가 어떤 문자를 나타내는지 알려줄 뿐, 그 숫자를 파일에 어떤 바이트로 저장할지는 정하지 않습니다. 그 역할을 하는 것이 UTF-8, UTF-16, UTF-32 같은 인코딩 형식입니다.
UTF-8: 승리한 인코딩
UTF-8은 1992년 켄 톰프슨과 롭 파이크가 설계했으며, 유니코드 코드 포인트를 1~4바이트로 인코딩합니다. 핵심은 하위 호환성입니다. ASCII 문자(U+0000~U+007F)는 정확히 1바이트를 사용하며, 그 바이트 값은 ASCII와 동일합니다. 즉, 유효한 ASCII 파일은 변환 없이 그대로 유효한 UTF-8 파일이 됩니다.
ASCII를 넘어서는 문자는 다중 바이트 시퀀스를 사용합니다. 라틴 악센트 문자와 많은 기호는 2바이트, 대부분의 아시아 문자(한글 포함)는 3바이트, 이모지와 희귀 역사 스크립트는 4바이트입니다. 첫 번째 바이트가 후속 바이트 수를 알려주므로, 스트림의 어느 지점에서든 다음 문자의 시작점을 찾을 수 있습니다.
UTF-8은 인터넷에서 지배적인 인코딩이 되었습니다. 2024년 기준 전 세계 웹 페이지의 98% 이상이 UTF-8을 사용합니다. HTML5, JSON, XML, 대부분의 현대 프로그래밍 언어에서 기본 인코딩입니다. 오늘 새 파일을 만든다면 UTF-8이 거의 확실한 정답입니다.
UTF-16과 UTF-32
UTF-16은 기본 다국어 평면(U+FFFF 이하)의 문자에 2바이트, 그 이상의 문자에 4바이트를 사용합니다. 자바와 자바스크립트는 내부적으로 UTF-16을 사용하는데, 이모지 하나가 서로게이트 쌍을 필요로 해서 문자열 길이가 예상과 다르게 나오는 이유가 여기에 있습니다.
UTF-32는 모든 문자에 정확히 4바이트를 사용합니다. 50번째 문자가 항상 바이트 오프셋 200에 있으므로 임의 접근이 간단하지만, ASCII나 라틴 기반 텍스트에는 공간 낭비가 심합니다. 파일 저장이나 전송에 UTF-32를 쓰는 경우는 드뭅니다.
인코딩이 여전히 중요한 이유
UTF-8으로 수렴하는 세상에서도 인코딩 문제는 계속됩니다. 레거시 시스템은 여전히 오래된 인코딩으로 파일을 생성합니다. 일부 스프레드시트의 CSV 내보내기는 UTF-8이 아닌 시스템 로캘 인코딩을 기본값으로 사용합니다. 데이터베이스 컬럼의 인코딩이 애플리케이션 레이어와 맞지 않을 수 있고, 이메일 헤더와 본문의 인코딩이 다를 수도 있습니다.
텍스트를 다룰 때는 항상 어떤 인코딩을 사용하고 있는지 확인하세요. 파일 생성, DB 연결, HTTP 응답 전송 시 UTF-8을 명시적으로 지정하세요. 외부에서 받은 텍스트는 처리 전에 선언된 인코딩을 반드시 확인하세요.
핵심 정리
새 프로젝트, 파일, 데이터베이스에는 UTF-8을 쓰세요. 다른 인코딩을 선택할 이유가 없습니다. 깨진 텍스트를 만났다면 인코딩 불일치가 원인일 가능성이 가장 높습니다. 인코딩 변환 도구로 기존 파일을 수정할 수 있지만, 장기적인 해결책은 항상 UTF-8 표준화입니다.
문자 인코딩은 보이지 않는 인프라입니다. 제대로 작동하면 아무도 눈치채지 못하고, 깨지면 텍스트가 읽을 수 없게 됩니다. 작동 원리를 이해하면 문제를 예방하고, 발생했을 때 빠르게 진단할 수 있습니다.