문자열 인코딩은 실무 소프트웨어 개발에서 중요한 기술 하지만, 인코딩으로 인한 문제가 생기기 전까지는 배울 기회가 없는 기술

아스키 코드, EUC-KR, UTF-8, UTF-16, UTF-32와 같은 단어를 한 번 이상은 들어봤어도 이 단어들이 무슨 뜻인지, 문자열 인코딩이 무엇인지는 정확히 모르는 경우가 많다

문자열 인코딩의 종류와 사용방법에 대해 알아보자

#문자열인코딩이란?

문자열 인코딩(character encoding)이란 2진법을 사용하는 컴퓨터가 인간의 언어를 일정한 규칙에 따라 2진수로 변환하는 방식 컴퓨터는 안녕하세요와 같은 문장을 그대로 읽거나 처리 할 수 없기 때문

그래서 컴퓨터는 사람들이 만든 2진수와 문자를 일대일로 대응하는 규칙을 통해 2진수로 문자를 처리함 앞서 이야기했던 아스키 코드, EUC-KR, UTF-8, UTF-16, UTF-32가 이러한 규칙에 포함된다. 문자열 인코딩 규칙은 정류에 따라 변환 방식이 조금씩 다르지만 원리는 간단하다.

2진수 01000001(10진수 65)는 문자 A다

2진수 01000001을 10진수(우리가 보통 쓰는 숫자가 10진수입니다로 읽으면 65가 되지만, 아스키 코드로 읽으면 문자 A가 됩니다. 파이썬 format() 함수를 활용하여 2진수를 다른 진수 및 문자열로 표현해보겠습니다 (코드 1-1))

   # 다음 코드를 실행하기 위해서는 별도 모듈이 필요하지 않습니다.
   ... 

#아스키코드(ASCII)

아스키 코드(ASCII)는 처음으로 표준을 정립한 문자열 인코딩 방식으로 아직까지 많이 사용됩니다. 사용할 수 있는 문자의 종류에는 대문자, 소문자 아라비아 숫자, 공백 및 특수 문자들이 있으며 문자를 표현할때는 0부터 127까지, 총 128개의 숫자를 사용합니다.

과거에는 7비트 2진수만 사용해지만, 현대 운영체제들은 성능 향상과 편의를 위해 8비트(1바이트)를 사용하여 아스키 코드를 표현합니다. (메모리 4바이트 정렬 참조)

#EUC-KR(CP949)

우리나라에서는 컴퓨터로 한긍를 표현하는 방법으로 EUC-KR 문자 집합을 만들었습니다. EUC-KR은 한국 산업 표준(KS)로 지정된 한국어 문자집합으로 문자하나를 표현하기 위해 2바이트를 사용합니다. 단, 아스키 코드 문자를 표현할때는 1바이트를 사용하기 때문에 아스키 코드와 호환됩니다. EUC-KR 문자표 일부이며 빈 곳을 포함해 가로로 총 16개의 문자가 있습니다. 가장 왼쪼겡 있는 코드(B0A0, B0B0)등 기준으로 오른쪽으로 한칸씩 이동할 때마다 1바이트 씩 더합니다. 예를 들어 ‘가’문자는 B0A0 코드 줄의 두번째 칸에 있어 1바이트를 더해 B0A1로 표현합니다. B0A1는 0xB0, 0xA1로 나뉘어 총 2바이트를 사용합니다.

EUC-KR은 모든 글자가 완성된 형태로만 존재하는 ‘완성형’ 코드입니다. 따라서 한글처럼 초성, 중성, 종성을 조합해 문자를 만들 수 없기 때문에 EUC-KR로 표현할 수 없는 한글이 일부 존재합니다. 물론 EUC-KR로 표현할 수 없는 글자들은 일반적으로 잘 사용되지 않긴 합니다. 유니코드 2.0 버전에서 초성, 중성, 종성에 해당하는 코드로 나눠 표현하는 조합형 글자를 만들면 EUC-KR로 표현할 수 없는 글자들을 만들 수 있습니다.

CP949는 EUC-KR을 확장한 문자 집합으로 EUC-KR과 같은 문자열 인코딩이나, 더 많은 문자를 표현할 수 있습니다. 오늘날에는 EUC-KR로 표기하더라도 실제로는 CP949 문자집합을 사용하는 경우가 많습니다.

...

영문자 ‘Hello’를 출력할 때 아스키 코드와 동일하게 5바이트를 사용했지만, 한글 ‘안녕하세요’를 출력하기 위해서 10바이트를 사용했습니다. EUC-KR로 아스키 코드 영역에 있는 글자를 표현할 때는 1바이트를 사용하지만, 한글 문자를 표현할 때는 2바이트를 사용하기 때문입니다.

이처럼 문자열 인코딩에서는 실제 문자열 길이가 버퍼 길이와 다른 경우가 많습니다. 실제 문자열 길이는 사랆 눈에 보이는 문자열 길이에 해당하고, 버퍼 길이는 컴퓨터가 문자를 표현하는 데 사용한 바이트 수를 의미합니다. 여기서는 버퍼는 메모리에 할당된 공간을 뜻합니다(예를 들어 변수를 선언해 숫자나 문자열 값을 넣거나, 새로운 객체를 생성하는 행위 등 모두 버퍼가 필요합니다). 그래서 실제 문자열 길이와 컴퓨터가 할당하는 버퍼 크기는 항상 다를 수 있다는 점을 꼭 기억하시길 바랍니다.

개발 환경에서는 실제 문자열 길이와 컴퓨터가 할당하는 버퍼 크기를 동일하게 취급해 생기는 버그가 생각보다 많습니다. 문자열을 취급할 때는 어떤 문자열 인코딩 방식을 쓰는지 반드시 알아야하고, 가능한 같은 문자열 인코딩을 사용하는 것이 좋습니다.

#유니코드(UTF-8, UTF-16, UTF-32)

과거에는 EUC-KR처럼 국가별로 독자적인 문자 집합과 인코딩 방식을 사용했습니다. 따라서 전 세계 사용자를 대상으로하는 프로그램이나 웹 페이지를 만들려면 언어별로 다른 인코딩 방식을 사용해야 했습니다. 언어별로 다른 메시지를 만들고 관리하는 것도 어려운데, 인코딩 방식까지 다르게 적용한다면 개발자 입장에서 너무 골치아픈 일이겠죠. 이렇게 국가별로 독자적인 문자열 인코딩을 사용하는 문제를 해결하기 위해 국제 표준화 기구(ISO)에서 동일한 규칙으로 모든 언어를 표현할 수 있는 유니코드 문자 집합을 만들었습니다. 최초 버전인 1.0은 1991년에 제정됐고, 이후 여러 언어를 추가하면서 12.1 버전까지 만들었습니다. 새로운 언어가 등장한다면 앞으로도 계속 개정될 것입니다. 유니코드 문자 집합을 표현하는 문자열 인코딩은 총 세 가지로 UTF-8, UTF-16, UTF-32가 있습니다. 아스키 코드나 EUC-KR처럼 문자 집합에 해당하는 하나의 인코딩 규칙만 있는게 아닙니다. 이어지는 절에서, 많이 사용되는 UTF-8과 UTF-16을 배워보겠습니다.

#UTF-8

  • 오늘날 가장 많이 사용하는 문자열 인코딩
  • 최소 1바이트, 최대 6바이트를 사용 (그러나 대부분 4바이트 내로 처리함)
  • 아스키 코드와 호환 가능함
  • 윈도우, 자바, 임베디드를 제외한 거의 모든 환경에서 문자열 처리 표준으로 봐도 무방
  • JSON은 UTF-8 인코딩만 사용하며, 다른 문자열 인코딩은 표준에서 지원하지 않음

#UTF-16

  • 자바와 윈도우는 유니코드를 사용하기 전부터 고정된 2바이트 길이의 문자집합을 사용함 (그래서 UTF-16은 멀티 바이트라고도 함)
  • 자바와 윈도우 환경에서의 호환성 외에 UTF-16을 사용할 이유는 없음
  • 2바이트 또는 4바이트 길이의 문자열을 사용하며, 아스키 코드와 호환되지 않음
  • UTF-16 기반 환경에서 UTF-8을 사용할 때는 사용 영역을 명확히 구분하는게 좋음(예를 들어 자바 기반 웹 서비스는 기본적으로 UTF-16을 사용하되, 외부(데이터베이스와 브라우저 간) 통신시 UTF-8로 변환하여 사용하는게 좋음)

#UTF-32

  • 4바이트를 고정적으로 사용
  • 반드시 UTF-32를 사용해야하는 환경이 아니라면 사용하지 않음

#EUC-KR

  • 한국에서 독자적으로 사용하는 문자열 인코딩
  • 고정된 2바이트를 사용
  • 가능하다면 UTF-8로 바꾸는 게 좋지만 현실적으로 어려운 경우가 많음
  • UTF-16과 경계를 명확히 구분하여 사용하는 게 좋음

#살펴보면 좋은 내용들

  • MySQL의 UTF-8 타입에는 utf8과 utf8mb4가 있음. utf8은 3바이트 까지 정상으로 처리하나, 4바이트 영역 문자는 처리하지 못함. 따라서 UTF-8과 완벽히 호환되는 문자 집합을 쓰고 싶다면 utf8mb4를 써야함
  • 국내에서 만든 서비스를 연동할 때는 EUC-KR을 사용하는 경우가 있으니 주의 (예:케이지이니시스 결제 모듈은 결제 요청 내역을 EUC-KR로 인코딩해야함)