Blog Content

    티스토리 뷰

    한글 그리고 인코딩

    초기 컴퓨터는 수치 연산 만을 위해 개발되었다.  그러나 당연한 이유로 문자 표현에 대한 필요성이 있었고  이로인해 만들어진 문자 집합의 개념이 현재도 사용되고 있는 ASCII ( American Standard for Code for Information Interchance ) 이다. 


    초기 ASCII 는 8Bit (= 체계로 0x00 부터 0x7F) 까지  알파벳의 대문자 ~ 소문자 외  제어 문자 , 특수문자 일부 까지 총 127개의 문자를 저장할수 있었다.

    "미국 표준" 이라는 의미에서 느낄수 있지만 미국 중심의 문자 SET의 한계가 있었고 , 즉 독일어 , 프랑스어 등 영어 외 유럽어의 수용을 위해 확장 ASCII  를 추가로 정의 하였다. 


    이러한 형태의 방식은 알파벳을 기초로 사용하므로  총  256개의 코드만 정의하면 문자 정보의 전달이 가능한 방식이지만 아시아 언어  (중국어 , 일본어 , 그리고 한국어 ) 를 표현하기에는 적합하지 않아 별도의  방식이 필요 했다. 


    한글인코딩 방식의 표준화 , 산업 표준의 변화 이력은 복잡하고 이를 암기하는 것은 별로 도움되는 일은 아닌듯 합니다


    다만  기억해야 할 일은  이 시절 산업 표준은 국내 컴푸터 제조사를 중심으로 2바이트 조합형을 표준으로 채택하여 개발이 이루어 지고 있었고 


    이러한 중요한 표준화의 고민  과정 중에 가장 큰 영향을 미친 사건은 바로 "윈도우"가  완성형 문자 SET을 그들의 표준을 정했다는 사실이다. 

    그후 그동안의 표준화 논란은  윈도우의 시장 지배력으로 인하여 통합되었고 결과적으로 지금까지  한글문제에 대한 고민에 항상 등장하는 EUC (Extended Unix Code ) -KR   


    이런 듯  국내 한글의 표준화 체계가 정리(?) 되어 안정화 되고 있을 무렵  인터넷의 확산과 더불어 전 세계의 문자를 하나의 코드 체계로 표준화를 하자는 거대한 움직임이 생겼다. 

    그 결과 전세계에서 사용되는 모든 문자집합을 하나로 모아 탄생시킨 것이 바로 "유니코드" 이다. 


    유니코드 1.0은 1991년 8월에 제정되었고 그 후 5년이 지나서 유니코드 2.0 , 그리고  2010년 10월에 6.0 까지 재정되어 있다. 



    UTF-8은 코드 포인트 범위에 따라 인코딩 방식이 다르다.

    한글 완성형의 코드 범위는 U+AC00~U+D7AF에 위치하므로 16개의 비트가 필요하다. 즉, UTF-8 인코딩에서 한글은 무조건 3바이트 인코딩이다





    • JAVA

    JAVA의 String에서 사용하는 인코딩은 UTF-16 BE (Big Endian) 이다.  

    문자열의  전송/수신을 위해서는 직렬화 ( Serialization ) 이 필요한데  이때는  (변형된)UTF-8이 사용된다.

    Java에서 문자열은 항상 UTF-16 BE 인코딩으로 저장되며, file.encoding시스템 프로퍼티에 의해 인코딩 값이 결정된다는 점이다. 

    특히 C언어를 많이 다루어 본 개발자라면 문자열을 C의 1바이트 char 배열로 여기는 경향이 강하기 때문에 이 차이점을 잘 이해해야 한다. 

    언어 차원에서 유니코드와 같은 캐릭터 인코딩을 지원하지 않는 C와 달리 Java에서는 언어 차원에서 유니코드와 여러 코드 페이지를 지원한다.

    Java는 String 객체 내부(메모리 상에서) UTF-16 BE 인코딩으로 문자열을 저장하고, 문자열을 입/출력할 때에만 사용자가 지정한 인코딩 값 또는 운영체제의 기본 인코딩 값으로 문자열을 인코딩한다. 

    JVM 기본 인코딩은 JVM 로딩 시에만 초기화되므로, 코드 중간에서 file.encoding 프로퍼티를 바꾸는 것은 아무 의미가 없다. 

    만약 file.encoding이 지정되어 있지 않다면, OS 환경 변수(예: LANG) 값을 따른다. 

    Java에서 글자를 깨뜨리지 않으려면, 문자 집합의 이름을 지정해야 한다. 

    예를 들어, 문자열 객체의 getBytes() 메서드를 이용하여 바이트 배열을 얻고자 할 때, getBytes() 대신 getBytes(String charsetName) 메서드를 사용하고, 반대로 바이트 배열에서 문자열 객체를 얻고자 할 때, new String(byte[] b) 대신 new String(byte[] bs, String charsetName) 메서드를 사용한다

    • Javascript 

    Javascript는 escape, encodeURI, encodeURIComponent 메서드를 이용하여 URL을 인코딩할 수 있다. 

    이 중 escape 메서드는 A~Z, a~z, 0~9, @*-_+./ 문자가 아니면 유니코드 형식으로 인코딩하는데, ASCII 문자는 %XX, 그 외는 %uXXXX 형태로 인코딩된다. 

    예를 들어, '한글'을 escape 메서드로 인코딩하면, %uD55C%uAE00으로 인코딩되므로, Tomcat에서 URL 디코딩 시에 문제가 발생하게 된다. 

    일반적으로 문자열을 URL 인코딩하기 위해서 encodeURI 메서드를 많이 사용하며, :;=?& 문자는 인코딩하지 않는다

    Java의 URLEncoder.encode 메서드와 Javascript의 encodeURI 메서드는 공백(whitespace)을 '%20'으로 인코딩하느냐, '+'로 인코딩하느냐만 다르다



    결론적으로 웹에서 한글에 왜 깨지는가에 대한 물음은  간단하게 대답하면  브러우저 인코딩값과 서버의 인코딩 값이 다르기 때문인데  

    서버의 인코딩에 대한 문제는  운영체게의 기본 인코딩, JAVA/JSP 의 인코딩 , HTTP 요청과 응답의 인코딩 그리고 DATABASE의 인코딩까지 확인해야 하는 어려움이 있다. 

    각 계층 별 환경의 조합으로 인한 문제를 해결 해야하니   무적이나 어려운 문제가 되어 버린다. 

    Comments