위키(웹)에서 작성된 텍스트 파일을 읽어 들여 특정 문자열을 변환 해야 하는 이슈가 있었습니다. 예를 들자면 :

= 제목 =
 * 내용1
 * 내용2

위의 내용중에서 '제목'이라는 문자열을 찾아 모두 '타이틀'로 변경 하는 작업이 필요하다고 생각하시면 됩니다.

변환 하는 방법이 그렇게 어렵지는 않을 것입니다. 간단히 생각을 해보면 :

  1. 디렉토리를 순회 하며 파일의 이름들을 얻어 온다.
  2. 파일을 열어 특정 문자열을 찾아, 변경 한다.
  3. 파일을 저장하고 다른 파일들에 대해 2번 과정을 적용한다.

그렇게 문자열을 처리하는데 편리한 기능들을 많이 제공하는 언어를 사용한다면 그렇게 어려운 일도 아닐 것 입니다. 파이썬을 이용하자면 아래와 같은 코드가 나올 수 있겠지요 :

import os
for root, dirs, files in os.walk('.') :
    for file in files :
        fp = open(file,'r')
        result = ''
        try :
            for line in fp :
                line = line.replace("변환대상문자열1", "변환문자열1")
                line = line.replace("변환대상문자열2", "변환문자열2")
                line = line.replace("변환대상문자열3", "변환문자열3")
                line = line.replace("변환대상문자열4", "변환문자열4")
                # 기타등등 문자열 변환
                result += line
        finally :
            fp.close()

        fp = open(file, 'w')
        fp.write(result)
        fp.close()

버그(변환 프로그램 자신도 변환 대상으로 인식해버리기 때문)가 있긴 하지만 아마도 한번(?) 정도는 원하는대로 돌아 갈 수도 있을 것입니다.

하지만 이 프로그램이 제대로 돌아갈까요? 제대로 돌아 갔었다면 제가 이 포스팅을 하고 있지도 않았겠지요. 물론 여러분의 기대와 같이 제대로 동작하지 않았습니다. 무엇이 문제 였을 까요?

바로 한글! 한글을 처리하는 인코딩에 관련된 문제 였습니다. 웹에서 작성된 텍스트 파일의 인코딩은 UTF-8이고 제가 작성한 파이썬 파일은 ASCII 였던 것이지요. UTF-8은 가변적인 길이를 가지는 인코딩 방법인지라 영어에서는 별 문제가 없지만 한글에서는 다른 인코딩 방법과 마찰을 일으킨답니다. 예를 들자면 유니코드의 '금'이라는 한글은 '0xAE08'입니다. 이진수로 변환해 보자면 '1010 1110 0000 1000'입니다. 하지만 이것이 UTF-8로 변환되면 '1110 1001 1011 1000 1000 1000'이라는 보다 더 긴 바이트를 가지게 되는겁니다.

컴퓨터가 보는 문자열은 당연히 치환하려는 문자열과 제가 파이썬 코드에서 작성한 문자열은 같지 않기 때문에 치환하고 싶은 문자열을 하나도 찾지 못 하겠다고 시치미를 뗄 뿐입니다.

자, 그럼 이걸 어떻게 알아 냈는가라는 것이 제가 이 포스트를 쓰게 된 첫 번째 이유이구요, 어떻게 해결 했는가 하는 것이 두 번째 이유입니다. 지금 부터 하나씩 알아가 보도록 하겠습니다.

첫 번째는 어떻게 알아냈는가 하는 문제에 관한 것입니다. 처음 변환 대상 문서를 열어 보니 :

吏€湲덇퉴吏€ vsftpd???먯껜 蹂댁븞 臾몄젣媛€ ?덉뼱 蹂댁븞沅뚭퀬媛€ ?섏삩 ?곸씠 ?놁쓣 ?뺣룄濡?蹂댁븞?깆씠 ?곗뼱?섎떎.[[BR]]

----
=== 湲곕낯 ?뺣낫 ===
 * OS : Red Hat Linux release 7.3
 * ?⑸룄 : GP 踰꾩텛???ъ씠?몄슜 ?쒕쾭 諛?媛쒕컻 ?뚯뒪?몄슜 ?ㅼ슫濡쒕뱶 ?ъ씠??

=== 二쇱슂 湲곕뒫 ===
- 媛€??IP蹂?蹂꾨룄???섍꼍 ?ㅼ젙 湲곕뒫 (?ㅼ젙?뚯씪??listen_address= ?댁슜) [[BR]]
- 媛€???ъ슜???ㅼ젙[[BR]]
- ?꾩넚 ?€??룺 吏€??[BR]]
- PAM 吏€??(踰꾩쟾 1.2.0遺€?곕뒗 PAM???듯븳 wtmp??濡쒓릿 濡쒓렇瑜??④?)[[BR]]
- xferlog ?쒖? 濡쒓렇 ?뚯씪蹂대떎 ?곸꽭???먯껜 濡쒓렇 ?뚯씪 ?뺤떇 吏€??[BR]]
- Standalone 諛⑹떇怨?inetd(xinetd)瑜??듯븳 ?댁쁺 紐⑤몢 吏€??[BR]]
- IP蹂??ㅻⅨ ?섍꼍 ?뚯씪 吏€??湲곕뒫 (tcp_wrappers?€ ?④퍡 ?ъ슜????[[BR]]

위와 같이 나옵니다. 딱봐도 인코딩이 깨진 것이 보이지요. 영어는 잘 보이지만, 한글 부분은 깨졌잖아요. vi가 기본적으로 보여 주는 인코딩 셋은 아마도 ASCII일 것입니다. 그렇다면 이 파일의 인코딩 셋은 무엇일까요? 리눅스에서는 'file'이라는 특정 파일의 정보를 얻어 내는데 도움이 되는 명령어를 제공하고 있습니다. 특히 인코딩 정보를 말입니다 :

[kukuta@server ~]$ file wikifile
wikifile: UTF-8 Unicode text
[kukuta@server ~]$ file pythonfile.py
pythonfile.py: ASCII Java program text

위의 두 파일의 인코딩 정보가 다르지요? 인코딩 셋이 맞지 않는 것 같다라고 생각이 되시면 언제든지 'file'을 이용하세요.

이제 문제를 해결 하는 것에 초점을 맞춰 보겠습니다. 지금 당장 우리에게 필요 한 것은 어떤 인코딩 방법으로 파일을 읽어들이느냐가 아닙니다. 어떻게 해서든지 파이썬 코드에서 작성된 '변환대상문자열1'이 웹에서 작성된 '변환대상문자열1'과 같다라는 것을 컴퓨터에게 알려야만 합니다. 크게 두 가지 방법이 있는데 한 가지 방법은 파이썬 버젼의 제약을 받는 것이고, 나머지 한 가지는 제가 아는 한도 내에서는 리눅스에서만 할 수 있는 것입니다(물론 윈도우에서도 할 수 있겠지만 제가 방법을 모릅니다).

첫번째 방법은 비교할 문자열을 'utf-8'로 인코딩 하여 비교하는 것입니다. 'How to use UTF-8 with Python'이라는 글에 잘 나와있습니다만, 저는 저 방법을 이용해서는 잘 안되더군요.

두 번째 방법은 파이썬 파일의 인코딩 셋을 utf-8로 변경 해 버리리는 것입니다. 만일 제가 '변환대상문자열1'이라는 문자열을 파이썬에 쓰고, 저장을 하게 된다면 단순 유니코드로 저장이 되겠지요. 하지만 이 파일의 인코딩 셋을 utf-8로 변경하게 된다면 우리가 변경하고자 하는 웹에서 작성된 텍스트 파일에 있는 문자열과 동일한 바이트를 가진 문자열로 변환 되는것 입니다. 리눅스에서는 파일의 인코딩 셋을 변경하기 위해 'iconv'라는 커맨드를 제공 하고 있습니다 :

[kukuta@server ~]$ iconv -f euc-kr -t utf-8 pythonfile.py --output pythonfile.py

위와 같이 하고 나면 유니코드로 작성되어 있던 한글이 utf-8로 변환 됩니다. 아까 제대로 보이던 한글은 이제는 깨져서 보일 것입니다만, 중요한 것은 컴퓨터가 변환하고자 하는 한글과 우리가 적은 한글이 동일함을 이제 부터는 안다는 것이지요.

Ref.

Posted by kukuta

댓글을 달아 주세요

  1. Favicon of http://blog.ggamsso.wo.tc BlogIcon 깜쏘 2008.02.24 23:45  댓글주소  수정/삭제  댓글쓰기

    저런 인코딩 문제 때문에 한글 프로그래밍이 힘들죠.
    맨날 하고 있는 짓이지만, 어떻게든 디코딩,인코딩을 없애고 싶은 사람중 하나임.
    utf8을 쓰자니, 한글 한 글자 뜯기 귀찮고, unicode 쓰자니 출력할 때 encoding 해야 하고...

    어떻게 해결 좀 해줘요.