기본 콘텐츠로 건너뛰기

[인코딩] MS949부터 유니코드까지

UHC = Unified Hangul Code = 통합형 한글 코드 = ks_c_5601-1987


이는 MS사가 기존 한글 2,350자밖에 지원하지 않던 KS X 1001이라는 한국 산업 표준 문자세트를 확장해 만든 것으로, 원래 문자세트의 기존 내용은 보존한 상태로 앞뒤에 부족한 부분을 채워넣었다. (따라서 KS X 1001에 대한 하위 호환성을 가짐)

그럼, cp949는 무엇일까? cp949는 본래 코드 페이지(code page)라는 뜻이라 문자세트라 생각하기 십상이지만, 실제로는 인코딩 방식이다. 즉, MS사가 만든 "확장 완성형 한글 (공식명칭 ks_c_5601-1987) "이라는 문자세트를 인코딩하는 MS사 만의 방식인 셈이다.


cp949 인코딩은 표준 인코딩이 아니라, 인터넷 상의 문자 송수신에 사용되지는 않는다. 하지만, "확장 완성형 한글" 자체가 "완성형 한글"에 대한 하위 호환성을 고려해 고안됐듯, cp949는 euc-kr에 대해 (하위) 호환성을 가진다. 즉 cp949는 euc-kr을 포괄한다.

따라서, 윈도우즈에서 작성되어 cp949로 인코딩 되어있는 한글 문서들(txt, jsp 등등)은 사실, euc-kr 인코딩 방식으로 인터넷 전송이 가능하다. 아니, euc-kr로 전송해야만 한다.(UTF-8 인코딩도 있는데 이것은 엄밀히 말해서 한국어 인코딩은 아니고 전세계의 모든 문자들을 한꺼번에 인코딩하는 것이므로 euc-kr이 한국어 문자세트를 인코딩할 수 있는 유일한 방식임은 변하지 않는 사실이다.) 물론 이를 받아보는 사람도 euc-kr로 디코딩을 해야만 문자가 깨지지 않을 것이다.

KS X 1001을 인코딩하는 표준 방식은 euc-kr이며 인터넷 상에서 사용 가능하며, 또한 인터넷상에서 문자를 송수신할때만 사용.(로컬하드에 저장하는데 사용하는 인코딩방식으로는 쓰이지 않는 듯하나, *nix계열의 운영체제에서는 LANG을 euc-kr로 설정 가능하기도 한걸로 보아, 운영체제 사에서 한글 인코딩 방식으로 채용하기도 하는 듯.)


끝으로 팁인데, 웹브라우져에서 인코딩을 열어보면, utf-8, iso-8859-1등 많은 인코딩 방식들이 있는데 그 사이에 '한국어'라고 써 있는 경우가 있다. 이것이 바로 euc-kr을 의미한다. 즉, euc-kr이 KS X 1001에 대한 유일무이한 인코딩방식이라는 방증인 셈이다.

---------------

그렇다면, 윈도우즈의 메모장에서 작성한 "한글이 포함된 jsp 파일"은 왜 누군가의 웹브자우져에서 깨져보이는 것일까?

스텝별로 살펴보자면,
1.프로그래머가 메모장으로 jsp파일을 만들게 되며, 여기의 한글은 윈도우즈 자체의 인코딩 방식(혹자는 UTF-16LE 인코딩 방식을 따른다고 주장, http://mwultong.blogspot.com/2006/11/cp949-ms949-euc-kr-ksc5601-1987.html) (근데 윈도우즈의 메모장 저장시 인코딩 가능한 목록을 살펴본 결과, ANSI, 유니코드, 유니코드 빅엔디안, utf-8 4가지가 있는데 이중 무엇이 윈도우즈의 기본 인코딩 방식인지는 모르겠음. 근거는 또 있는건지. nhn 헬로월드의 한글인코딩 글을 보면, cp949가 윈도우즈 공식 한글문서 인코딩 시스템인듯 한데... 미결로 남김.)

2.클라이언트가 이 웹서버에 hangul.jsp파일을 요청하면, cp949로 인코딩된 jsp파일을 내려받게 되고, 클라이언트의 웹브라우저(ie, chrome, firefox)에서는 기껏해야 디코딩방식을 euc-kr, iso-8859-1, utf-8,utf-16 등으로 해석을 시도하는데, 이중 무엇으로 해도 깨진 결과가 나옴. 왜냐하면, 브라우져는 디코딩할 방식중 cp949(ms949)를 아예 배제하기 때문이다.

---------------

이 문제를 해결하기 위해서는?

1.프로그래머가 메모장으로 jsp파일을 만들게 되며, 여기의 문자들을 utf-8로 저장. 당초에 cp949를 통해 코드화해서 웹상으로 전송한다면, 브라우져상에서 정상적으로 볼 방법이 없다. 물론, 그냥 다운받아서, 윈도우즈 내장 프로그램인 메모장으로 열어본다면, 메모장의 기본 디코딩 방식인 cp949와 궁합이 척 맞아 떨어지며 한글이 우아한 자태로 잘 뿌려지겠지만 말이다. (즉, 웹브라우져로 깨진다고 해서, 메모장으로 못보는것이 아니다. 어디까지나 우리가 받는 내용은 모두 바이트 스트림이며, 이를 어떻게 해석하느냐의 문제다.)

2. 클라이언트가 hangul.jsp파일을 웹브라우져를 통해 열게되면,utf-8로 해석을 시도하게 됨. 암호화키와 복호화키가 같으므로 본래의 한글이 정상적으로 출력됨.만약 cp949로 복호화(실제 암호화란 뜻보단 코드화 되었다는 뜻으로 사용하고 있음) 되어 왔다면 웹브라우져의 제한된 디코딩방식으론 한글을 볼 방법이 전혀 없는 셈.

********************************************************
질문1.윈도우즈 운영체제는 한글을 분명 cp949 인코딩 방식으로 파일을 저장한다. 그렇다면 이를 메모리상에 올릴 때는, 바이트를 그대로 올려놓고, 화면에 뿌려줄때마다 디코딩을 하는 것인가/ 아니면 메모리에 올리는 과정에 디코딩이 포함되어 있어서 (예를 들어) ks_c_5601-1987 코드세트의 CCS(Coded Character Set)의 code번호들이 메모리에 나열되어 있는 것인가?

전자 후자에 따라 인터넷으로 전송하는데 다른 방식으로 나뉘게 되는데,..
1.



================================================================
실험결과 공유


<HTML>
<HEAD><META http-equiv="Content-Type" content="text/html;charset=euc-kr">
<TITLE>°£´ÜÇÑ ¿¹Á¦</TITLE></HEAD>
<BODY>¾È³çÇϼ¼¿ä HELLO</BODY>
</HTML>

이것은 현재 우분투 상에서 cp949(어이없게도 와인 노트패드는 이를 안시 인코딩이라 부름)로 인코딩 된 내용을 긁어붙인 내용이다. vi상에서도 위와 동일한 모양으로  한글이 깨져나온다. 그도 그럴것이, vi는 현 우분투의 기본 언어셋인 ko-KR.utf-8로 해석을 시도하기 때문이다.

어쨌거나 위 메타정보 덕분에 ie로 열어보았을 때 문자 인코딩 정보를 바탕으로 euc-kr로 디코딩 하는 것이 기본으로 되어있어 깨짐 없이 출력이 가능하다. 반면, 메타정보를 없애면, iso-8859-1 서유럽권 방식으로 디코딩을 시도해 파일이 깨지게 된다. 메타 정보를 지금 보내는 파일이 어떤 형식으로 인코딩 되어 있는지를 나타냄으로써 상대가 어떤 기준으로 다시 디코딩할지를 알려주는 역할만 할 뿐이다.

jsp파일에서는 html의 메타를 사용하는게 아니고, JSP문법의 page지시자를 사용한다.
<%@page contentType="text/html; charset=euc-kr"%>
<HTML>
<HEAD><TITLE>°£´ÜÇÑ ¿¹Á¦</TITLE></HEAD>
<BODY>¾È³çÇϼ¼¿ä HELLO</BODY>
</HTML>

마지막으로 서블릿클래스에서는 doGet메소드 안에서 마크업을 print하기 전에
HttpServletResponse형 객체인 response를 이용해서 다음과 같이 인코딩 정보를 알린다.
response.setContentType("text/html;charset=euc-kr");

예를 들면,
import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
public class HundredServlet extens HttpServlet{
    public void doGet(HttpServletRequest request,
                                       HttpServletResponse response)
                                       throws IOException, ServletException {
        int total =0;
        for (int cnt=1; cnt <101; cnt++){
            total += cnt;
        response.setContentType("text/html;charset=euc-kr");
        PrintWriter out = response.getWriter();
        out.println("<HTML>");
        ....중략....
    }
}

----------------------------------------------------------------------------------------------------------

참고. 사실, 위 깨진 내용을 vi로 긁어서 붙였기 때문에 깨져보일뿐, 노트패드로 열어서 정상적으로 출력되는 내용을 긁어붙였다면 정상적인 한글로 출력이 될것이다. 아래처럼 말이다.

<HTML>
<HEAD><META http-equiv="Content-Type" content="text/html;charset=euc-kr">
<TITLE>간단한 예제</TITLE></HEAD>
<BODY>안녕하세요 HELLO 똠방각하입니다.</BODY>
</HTML>

이것이 뜻하는 바는 무엇일까? 두 경우 차이점은 연 에디터가 다르다는 것 뿐이고, 공통점은 둘 모두 같은 바이트들의 나열인 우분투 파일시스템의 한 파일노드를 가리키고 있다는 점이다. 즉, 같은 파일을 열었지만 에디터의 속성을 탄다는 소리는, 메모리상에 올라갈 때 이미 디코딩이 이루어진다는 소리이기도 하다.

상식적으로, 문자세트와 인코딩방식이 다른 경우들 때문에, 고민해 봐야할 문제가 생겼다. 과연, 인코딩된 파일은 메모리로 올라갈때 인코딩된 내용 그 자체가 해독없이 바로 로드될까?

정답은 잘 모르지만 상식적인 선에서 가상 시나리오를 써보자면 다음과 같다.
vi에서 한글파일 저장시 인코딩을 따로 설정하지 않는다. 이는 운영체제의 기본 인코딩인 utf-8로 자동 변환이 이루어져 바이트의 연속으로 저장된다는 소리다. 그렇다면 이를 다시 vi로 열어 볼때는 당연히 운영체제 기본 인코딩 방식인 utf-8에 입각해 디코딩을 하게 될것이다.그러니깐 잘 보인다.

하지만 당장 윈도우즈의 간단한 메모장만 해도 한글파일 저장시 인코딩방식을 선택할 수 있도록 되어있다. ANSI(CP949를 칭하나 말도 안되는 명명법..), 유니코드16(세상에 유니코드 인코딩은 없다.) 유니코드16빅엔디안(유니코드는 문자셋을 가리킬 뿐이다.) utf-8(유일한 정상적인 인코딩 이름) 이렇게 4가지가 있다. 즉, 메모장으로 파일을 저장시 파일의 헤더부분에 인코딩관련 정보를 매직넘버로 저장하겠거니 하고 추측이 가능하다. 윈도우즈의 기본 인코딩 방식인 cp949로 바로 해석을 시도하기 보단, 파일에 '저장시 어떤 인코딩을 썼나' 하는 정보를 가지고 디코딩해 보여주기 때문에 한글은 깨지지 않고 잘 출력되게된다.

여기서 결론을 내리자면, 운영체제는 파일로 한글을 저장시 단 하나의 인코딩 방식을 강요하지도 않고 그럴 수도 없다. 운영체제는 파일 시스템을 제공하고, 이 위에 각 파일을 바이트들의 연속으로 저장할 뿐이지, 이를 해석하는 문제는 에디터 각 고유의 속성일 뿐이다. 파일에 인코딩관련 속성이 따로 없다면 운영체제의 기본 인코딩 방식으로 디코딩을 시도할테지만 말이다. (이것덕분에 윈도우즈에서 작성된 텍스트 파일이 우분투에서는 깨져 보이는 것이다. vi는 윈도우즈 출신 텍스트파일에 적힌 인코딩 정보를 해석할 능력이 없으므로. 하지만 고급 에디터인 emacs등으로 열어본다면 한글은 잘 출력된다. 다시 정시하건대, 이는 모두 복호화와 암호화의 pinch문제다.)

두번째 궁금증은, 메모리에 올라갈 때의 문제다. 아스키 코드의 경우엔 문자셋 자체가 인코딩 방식이기도 하다. 단순한만큼 문자셋 자체의 문자별 코드(숫자를 칭함)의 대응관계를 그냥 인코딩 방식으로 끌어다 쓰기 때문이다. 그런데 문제는 가변 인코딩 방식(MBCS - Multi Bytes Character Set)때문에 생긴다. 예를들어 유니코드 자체는 2바이트의 WBCS(Wide Bytes Character Set)로 고정된 비트별로 세계 각국의 문자 이미지를 대응시켜놓았다. 그런데 이를 그대로 인코딩 방식으로 쓰려니 기존 아스키코드에 대한 호환성 문제가 대두된다. 그래서 유니코드상의 한글 '가'는 U+AC00이지만, 유니코드 인코딩 방식 중 대표적인 utf-8에서는 '\xea\xb0\x80'로 쓰이게 된다. 즉, 호환성때문에 한다리면 충분할 걸
'가' <-----> 'U+AC00' <-----> '\xea\xb0\x80'
로 두다리를 건너야만 하게 된 것이다.

당초 제기한 궁금증을 더욱 구체적으로 정리하자면 이렇다. utf-8형식으로 '가'라는 문자를 파일로 저장하면 당연히 '\xea\xb0\x80'의 비트스트림으로 저장된다. 그런데 이 파일을 읽어 에디터 등으로 읽거나 한다면 메모리 상에 적재될텐데, 이때는 과연 메모리엔 '\xea\xb0\x80'라 쓰일까? 만약 그렇다면 문자 이미지를 표현하기 까지 아직 건너야할 다리가 2개인 셈이다. 문자를 화면에 표현(그림그리기)하기 까지 매 문자별로, 화면을 invalidate()할 때마다 다리를 2개씩 건너야 하는셈이다. 내가 운영체제를 설계한다면 아마 저렇게 하지 않을 것이란 의구심이 든다.

그럼 더 나은 방법은 뭘까? 우리가 텍스트 파일을 읽으면, 파일 헤더로부터 인코딩의 정보를 얻을 수 있고, 이를 바탕으로 메모리 적재 바로 전에 Unicode의 code point 들로 메모리를 채울 수 있을 것이다. 문자가 저장되는 메모리영역에는 단순히 raw bit들만 있는게 아니라, 이를 해석할 근거인 문자세트를 가리키는 포인터가 각 문자열별로 있지 않을까(운영체제 정도의 큰 프로그램 안에 유니코드 문자셋 테이블, ks x 1001 문자셋테이블이 없을리가 없다. 하다못해 언어 패키지 설치시에 설치가 가능할 것이다.)? 즉,MBCS형의 utf-8로 저장된 텍스트 파일일지라도, 더블클릭해 에디터로 읽는 순간 모두 WBCS의 2바이트 고정으로 유니코드 코드 포인트로 변환되어 메모리에 올라갈 거란 말이다. 이렇게 된다면 해석시에도 다리는 한개만 건너면 되며, 다른 형태의 인코딩으로 변환하는 작업시에도 메모리 상에서
cp949-> ks_c_5601-1987 -> unicode -> utf-8의 변환이 이루어지는게 아닌,
ks_c_5601-1987 -> unicode 이면 충분해 지며,
이것을 파일로 저장할 때만 utf-8로 다시 인코딩 하는 작업이 이루어 질 뿐이고, 인터넷으로 정보를 전달할 시에도 마찬가지로 인코딩 작업이 필요하게 되는 식이 될 것 같다.

정리하자면, 메모리에는 어느 한 문자셋트의 문자별 코드에 해당하는 값이 직접 있어야 하며, 이는 모두 디코딩 된 상태를 의미한다. 덕분에 이 메모리 상의 문자열들은 한다리만 건너 바로바로 해당 문자 이미지로 매핑이 되며 화면에 표시가 가능해진다. 여기에 이런 문자셋을 어떻게 표현해 인터넷을 보내든, 파일로 내보내든의 문제는 따로며, 파일로 내보내는 경우 에디터에서 인코딩방식을 설정하는 옵션이 있다는 사실도 이런 시나리오에 아귀가 맞아 떨어진다. (사실 생각해보니, 인터넷으로 내보낸다고는 했으나, jsp파일이나 txt파일은 그냥 인코딩 되어 있는 상태를 보내는 것이니 여기 내용과는 상관이 없고, 오히려 채팅 등의 프로그램에서는 매우 연관이 깊은 내용이다.)

댓글

  1. 질문이 잇어서 댓글을 올립니다.
    리눅스(AIX)에서 확장한글 처리를 위해
    Iconv_open("utf-8","cp949")
    를 사용하려고 하는데 변환이 안되고
    오류만 나고 잇습니다.
    Iconv -l 을 쳐도 cp949는 나오지 안는데
    추가로 라이브러리를 추가해야하는지 혹시 알고 잇으신게 잇으시면 알려주시면 감사하겟습니다

    답글삭제

댓글 쓰기

이 블로그의 인기 게시물

[linux] 뻔하지 않은 파일 퍼미션(file permissions) 끄적임. 정말 속속들이 아니?

1. [특수w]내 명의의 디렉토리라면 제아무리 루트가 만든 파일에 rwxrwxrwx 퍼미션이라 할지라도 맘대로 지울 수 있다. 즉 내 폴더안의 파일은 뭐든 지울 수 있다. 2. [일반rx]하지만 읽기와 쓰기는 other의 권한을 따른다. 3.[일반rwx]단 남의 계정 폴더는 그 폴더의 퍼미션을 따른다. 4.[일반]만약 굳이 sudo로 내 소유로 파일을 넣어놓더라도 달라지는건 없고, 단지 그 폴더의 other퍼미션에 write권한이 있으면 파일을 만들고 삭제할 수 있다. 5.디렉토리의 r권한은 내부의 파일이름 정도만 볼 수있다. 하지만 ls 명령의 경우 소유자, 그룹, 파일크기 등의 정보를 보는 명령어므로 정상적인 실행은 불가능하고, 부분적으로 실행됨. frank@localhost:/export/frankdir$ ls rootdir/ ls: cannot access rootdir/root: 허가 거부 ls: cannot access rootdir/fa: 허가 거부 fa  root #이처럼 속한 파일(폴더)만 딸랑 보여준다. frank@localhost:/export/frankdir$ ls -al rootdir/ # al옵션이 모두 물음표 처리된다.. ls: cannot access rootdir/root: 허가 거부 ls: cannot access rootdir/..: 허가 거부 ls: cannot access rootdir/.: 허가 거부 ls: cannot access rootdir/fa: 허가 거부 합계 0 d????????? ? ? ? ?             ? . d????????? ? ? ? ?             ? .. -????????? ? ? ? ?             ? fa -????????? ? ? ? ?             ? root 하지만 웃긴건, r에는 읽기 기능이 가능하므로 그 폴더 안으로 cd가 되는 x권한이 없더라도 어떤 파일이 있는지 목록 정도는 알 수 있다. 하지만 r이라고

[javascript, jquery] Event Bubbling / Event Delegation

source: http://www.mattlunn.me.uk/blog/2012/05/what-does-event-bubbling-mean/ What does “event bubbling” mean? “Delegation” and “bubbling” are terms that gets thrown round a lot in JavaScript; but what exactly do these terms mean? This is the first in a series of posts on bubbling, delegation and how to delegate events with jQuery;  What does event bubbling mean ,  Event Delegation in JavaScript  and  Event Delegation with jQuery Event Bubbling In JavaScript, events  bubble . This means that an event propagates through the ancestors of the element the event fired on. Lets show what this means using the HTML markup below; <div> <h1> <a href="#"> <span>Hello</span> </a> </h1> </div> Lets assume we click the  span , which causes a  click  event to be fired on the  span ; nothing revolutionary so far. However, the event then propagates  (or  bubbles ) to the parent of the  span