EUC-KR과 UTF-8을 알고가자

임준영·2021년 4월 10일
0

EUC-KR과 UTF-8을 알고가자

개발자라면 반드시 알고 있어야 되는 인코딩의 개념에 대해서 다시 한번 생각해보고 블로그를 보고 다시 공부하였습니다.

고객사에서 저희 서버에 Restful 방식으로 파일경로가 포함된 url을 Base64로 인코딩 하여 POST 방식으로 던지는데, 서버 쪽에서 디코딩을 하여 로그를 찍어보니... 한글이 들어오는 경우 ????.pdf로 찍혀있는 것을 확인하였습니다.

분명.. 인코딩 디코딩에 대해서 테스트 코드를 작성하였는데.. 무엇이 잘못된 것일까요? 로그를 봤을 때 실제로 테스트 코드에서 Base64 인코딩 한 값이랑 고객사에서 전달한 값이 다르다는 것을 확인하였고, 고객 사에서는 EUC-KR로 인코딩을 하여 Base64로 인코딩 하기 때문에... 한글 명이 포함된 URL을 UTF-8로 디코딩을 하였을 때 당연히.. 깨질 수 밖에 없었다는 것을 깨달았습니다.

그래서 다시 인코딩에 대한 개념을 알기 위해서 컴퓨터가 문자열을 저장할 때 어떻게 저장하고 표현하는지 살펴보았습니다. 먼저 2진수 16진수에 대해서 알아보겠습니다.

2진수와 16진수

컴퓨터는 모든 데이터와 명령을 2진수로 처리합니다. 반도체 기억소자가 켜져 있는 상태나 꺼져 있는 상태, 즉 1 또는 0에만 있을 수 있기 때문입니다.

0 또는 1의 한자리 2 진수 정보를 저장할 수 있는 단위를 비트(bit) 라고 합니다. 1비트의 저장 공간으로는 두 가지 기호 밖에 구분할 수 없습니다.

1바이트로 나타낼 수 있는 기호의 개수는 2의 8승 즉, 256개입니다.

컴퓨터가 사용하는 2진수로 값을 표현하면 자릿수가 길어 씍도 읽기도 불편합니다. 그래서 컴퓨터의 값을 표현할 때는 2진수 대신 16진수를 많이 씁니다.

16 진수는 16개의 기호를 사용합니다.

  • 0 ~ 9의 10개의 숫자와 A ~ F의 6개의 문자를 사용합니다.

16진수는 2진수 4자리를 한자리로 표현할 수 있습니다.
10진수 10을 2진수로 표현하면 1010, 16진수로 표현하면 A입니다.

2진수 8자리, 즉 1byte를 두 자리의 16진수에 익숙해져야 합니다.

1. 인코딩과 디코딩

컴퓨터는 일반적으로 0과 1밖에 모르는.. 슈퍼 바보입니다.
우리 인간들이 사용하고 있는 문자를 컴퓨터에 저장하기 위해서는 각각의 문자를 2진수로 변환해야 합니다.

이렇게 문자를 컴퓨터에 저장하기 위해 숫자(2진수)로 변환하는 것을 인코딩이라고 하고, 반대로 인코딩한 숫자를 읽기 위한 문자로 되돌리는 것을 디코딩이라고 합니다.

아래 예시를 하나 들어보겠습니다. 한글은 기본적으로 2바이트로 표현됩니다.

ex) 인코딩
========> 10110000 10100001 (16진수로 표현하면 B0A1)

ex) 디코딩
<======== 10110000 10100001

컴퓨터 운영체제는 각 나라의 문자를 숫자로 변환할 수 있도록 다양한 인코딩 방법을 제공하는데, 그 중 한글을 변환할 수 있는 인코딩 방식 중 개발자들 입에 자주 오르는 EUC-KR과 UTF-8에 대해 알아보겠습니다.

2. EUC-KR

EUC-KR은 한글을 2byte로 변환하는 방법입니다. 문자마다 2byte의 코드 값이 정해져 있습니다.

의 행번호와 열 번호를 조합하면 B0A1이다.
즉, EUC-KR에서 한글 의 숫자 값은 B0A1이라고 미리 정해 놓은 것입니다.

B0A1은 16진수 4자리로 표현한 2byte 값이고, 실제 컴퓨터에 저장할 때는 2진수 10110000 10100001로 저장됩니다.

뭔가 복잡해보이는 알고리즘이 있을 것 같았지만, 실제로는 미리 정해놓은 코드 표를 이용하는 것입니다.

ex) EUC-KR 인코딩
=========> B0 A1 (10110000 10100001)

컴퓨터는 를 EUC-KR로 인코딩 하기 위해 EUC-KR 코드 표에서 의 코드 값을 찾아 2진수로 저장합니다.

3. 유니코드와 UTF-8

EUC-KR은 한글을 2byte로 변환하는 인코딩 방법이라고 했습니다.
사실, EUC-KR 코드표에는 한글뿐 아니라 숫자, 특수 기호, 영문, 한문, 일어가 정의되어 있습니다. 이외에 다른 문자를 사용하는 나라의 언어는 인코딩할 수 없습니다.

서로 다른 언어를 사용하는 컴퓨터들이 서로 문제없이 통신할 수 있도록 전 세계의 모든 문자를 하나의 통일된 문자집합(charset)으로 표현하고자 노력하였고 그 결과의 산물이 바로 유니코드입니다. 참고로 Java의 문자셋은 유니코드를 채택하고 있습니다.

유니코드는 다양한 문자를 모아 놓고 순서대로 번호를 붙여놓았습니다.
유니코드에는 뭐라고 읽는지 알 수도 없는 희한한 문자들이 많습니다.

이 문자들을 번호로 다루는 것이 편리합니다.

이렇게 문자마다 붙여 놓은 번호를 코드 포인트(code-point)라고 하고, 앞에 U+를 붙여 표현합니다. U+는 유니코드를 의미합니다.

예를 들어, 의 코드 포인트는 AC00이고 U+AC00으로 표현합니다.

유니코드 인코딩 방법에는 UTF-8, UTF-16, UTF-32 3가지가 있습니다.
만약 한글 를 유니코드 UTF-8 방식으로 인코딩한다고 하면 그 과정은 아래와 같습니다.

  • 유니코드 코드표에서 의 코드포인트를 찾습니다.
    • 의 코드포인트는 U+AC00입니다.
  • 의 코드 포인트를 UTF-8 방식으로 인코딩 합니다.
    • 를 UTF-8로 인코딩 하니 EA B0 80이라는 3byte 값이 되었습니다.

그럼 대체 UTF-8은 의 유니코드(U+AC00)를 어떤 방법으로 3byte 값(EAB080)으로 인코딩하는 것일까요?

위의 그림에서 보이는 표는 정의되어 있는 유니코드 범위에 따라 UTF-8로 인코딩 하는 방법을 정리해 놓은 것입니다.

의 코드포인트는 U+AC00이고 , 2진수로 표현하면 10101100 00000000 입니다.

U+AC00은 U+0800 ~ U+FFFF 범위에 있으니 위 인코딩 방법에 따라 1110xxxx 10xxxxxx 10xxxxxx의 x 자리에 순서대로 유니코드의 값을 채워 넣으면 됩니다.

의 코드포인트 2진 수 값을 앞에서부터 채워보겠습니다.
11111010 10110000 10000000 (16진수 => EA B0 80)
이와 같은 방식으로 의 인코딩 값이 3byte의 EA B0 80이 된 것입니다.

이렇게 UTF-8은 유니코드 범위에 따라 1 ~ 4byte로 인코딩하는 가변 크기 인코딩 방식입니다. 사용 빈도가 높은 글자는 적은 공간을 차지하고 사용 빈도가 낮은 글자는 많은 저장 공간을 차지하게 하려고 만든 인코딩 방식이 UTF-8 입니다.

UTF-32는 모든 문자를 4바이트(32비트)로 표현합니다.
모든 문자를 일관되게 4바이트로 표현하므로, 소프트웨어가 특별한 고려를 할 필요가 없이 일관성 있게 문자를 처리할 수 있다는 장점이 있습니다. 그러나 하나의 문자를 저장하는데 너무 많은 저장공간이 소요되는 것이 단점입니다.

UTF-16은 사용 빈도가 높은 글자는 2바이트로 표현하고 사용 빈도가 낮은 글자는 4바이트로 표현합니다.

참조 사이트: https://blog.naver.com/bbmobile/221360230141

0개의 댓글