제육's 휘발성 코딩
article thumbnail
반응형

인코딩이란? 

인코딩이란 어떠한 정보를 특수한 목적을 가지고, 다른 형태로 변환하는 행위를 의미합니다.


컴퓨터에서 문자를 저장, 전송, 연산하기 위해서는 모든 데이터를 0과 1로 바꿔야 합니다. 이때 사용하는 방식도 인코딩에 속합니다. 즉, 문자 인코딩은 문자를 컴퓨터에서 사용할 수 있는 2진수(0,1)로 변환하는 것입니다. 반대로 숫자로 변환한 데이터를 다시 원래 정보인 문자로 되돌리는 것을 디코딩이라고 합니다. 

 

컴퓨터가 0과 1로 연산하기 위해 데이터를 인코딩한다면, 값에 맞게 매핑하는 기준이 있어야 할 텐데 기준이 뭘까? 

 

ASCII 문자 집합 등장

 

아스키 표 (출처 : https://commons.wikimedia.org/wiki)

ASCII (American Standard Code for Information Interchange) 테이블은 컴퓨터에 사용할 문자를 2진수로 인코딩하기 위한 7비트의 고정 길이 코드 체계로 영문 알파벳, 숫자, 특수 문자 등을 표현합니다.

 


ASCII 테이블은 한글이 없는데, 한글은 어떻게 표현될까? 먼저 한글의 특징부터 알아보자.

 

한글 (조합형, 완성형)

한글의 총 글자수로 11,172 자가 존재하기 때문에 아스키 테이블과 같이 256자로 처리하는 1바이트(8비트) 체계는 절대 불가능한 상황이었죠. 더군다나 한 글자로 표현되는 대부분의 언어와 달리 자음과 모음을 조합하여 글자를 표현하는 특이한 케이스기 때문에 한글을 숫자로 표현하기 위해 조합형과 완성형 방식이 등장하게 됩니다. 

 

조합형 방식

조합형 방식 (출처 : https://ko.wikipedia.org/wiki)

조합형 방식은 자음 + 모음 또는 초성 + 중성 + 종성을 조합하여 글자를 만들어내는 방식입니다. 예를 들어 "밥"을 "ㅂ + ㅏ + ㅂ"으로 표현하는 방식이죠. 

조합형은 2 바이트 체계로 총 16비트에서 앞 1비트는 한글임을 알리는 비트로 사용하고 나머지 15비트는 초성, 중성, 종상을 각 5비트 (0 ~ 31)로 구분지어서 사용합니다.

 

자음과 모음의 모든 조합을 표현할 수 있다는 장점이 있지만, 조합형은 두 번째 조합인 중성(모음)의 첫 비트가 0이면 다른 ASCII 코드와 충돌할 수 있다는 단점과 규격이 단일화되지 않은 문제가 있었습니다. 

 

완성형 방식

완성형 방식은 "쀍, 칢, 꺍"과 같은 사용빈도가 낮은 글자들을 제외하고 한글의 모든 글자(가 ~ 힣)를 각각 숫자로 매핑한 방식입니다. EUC-KR, CP949, MS949 등이 완성형 인코딩 방식을 사용하고 있어요.

모음과 자음의 조합을 해석하는데 들어가는 비용이 줄어들어 조합형보다는 효율적인 방식이지만, 완성형 또한 사용하지 못하는 글자가 있다는 치명적이 단점이 남아있었죠. 

어떤 사람이 배달앱으로 요청사항에 김 빼주세요를 김 주세요라고 적었다가 김?주세요로 인코딩이 깨져서 요청사항에 등록된 바람에 김이 배달 왔다는 등.. 의 문제가 있죠.

 

유니코드의 등장

유니코드 기본 평면 - 1칸 당 256자 (출처 : https://ko.wikipedia.org/wiki)

한글을 처리하기 위한 대혼란 속에 1991년 전 세계 모든 문자를 매핑하는 문자 집합인 유니코드가 등장하게 되었어요. (전 세계 문자가 모두 들어가 있는데, 한글은 한자 다음으로 가장 많은 코드를 차지하고 있다고 하네요.) 

 

유니코드는 완성형과 같이 각 글자에 숫자를 매핑한 방식으로, 문자 하나를 4바이트(32비트)로 저장하고 있었어요. 즉 ASCII가 1바이트 공간을 차지하니 비용이 4배가 들게 된 셈이죠. 이 문제를 보완하기 위해 가변길이 문자 UTF-8, UTF-16 등이 등장했죠.

 


UTF-8 (Unicode Transformation Format-8 bit)은 가변 길이 문자 인코딩 방식으로, ASCII 포함 전 세계의 문자를 지원(1바이트 ~ 4바이트)하며 한글을 표현하는 데는 3바이트를 차지합니다.


UTF-8 VS EUC-KR

주로 사용되는 인코딩 방식인 UTF-8과 EUC-KR을 Java에서 비교 해보자. Java에서 String 클래스는 Unicode 문자로 이루어져 있습니다. 

// JVM 인코딩 방식 
System.out.println(System.getProperty("file.encoding")); // EUC-KR

String word = "가나다라마바사";
byte[] eurKrWords = word.getBytes(); // 인코딩 방식 미지정으로 JVM 인코딩 방식 채택
byte[] utf8Words = word.getBytes(Charset.forName("UTF-8"));

String wordA = new String(eurKrWords);
String wordB = new String(utf8Words, Charset.forName("EUC-KR"));

System.out.println(wordA); // 가나다라마바사
System.out.println(wordB); // 媛????ㅻ?쇰?諛???
System.out.println(eurKrWords.length); // 14
System.out.println(utf8Words.length); // 21

System.getProperty("file.encoding")을 호출하면, JVM에서 사용되고 있는 기본 문자 인코딩 방식을 확인할 수 있습니다. 

 

IntelliJ > Help > Edit Custom VM Options > idea.vmoptions

JVM 설정 파일을 보면 저의 경우 EUC-KR로 지정해두었기 때문에 EUC-KR로 동작하는 것을 볼 수 있습니다. 대부분 디폴트로 사용하는 UTF-8로 선택되어 있습니다.

 

wordA는 byte가 default encoding인 EUC-KR 방식으로 인코딩 되어 정상 출력 되었지만, wordB는 인코딩이 깨진 현상을 볼 수 있습니다.

String wordB = new String(utf8Words, Charset.forName("UTF-8"));
String wordC = new String(wordB.getBytes(Charset.forName("EUC-KR")));
  • UTF-8 형태의 바이트를 유니코드 형태인 String으로 변환하고, String을 다시 EUC-KR로 변환하면 인코딩이 깨지지 않고 정상 출력이 가능해집니다. 



String wrongWord = "쀍";
String wrongWord2 = "김뺴주세요";
System.out.println(wrongWord); // ?
System.out.println(wrongWord2); // 김?주세요
  • EUC-KR은 완성형 채택하고 등록되지 않은 문자는 실제로 출력해봐도 동일하다. 

 

 

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^