문서의 Charset 을 detecting 하는 library 로는 IBM 이 지원하는 International Components for Unicode (
ICU Project) 의 ICU library 와 Mozilla Browser 에서 이용하는 Universal Chardet library 가 있습니다.
ICU 의 경우에는 charset detect 가 포함된지 꽤 되었음에도 불구하고, php 5.3 부터 기본 포함되는
intl extension 에는 이 기능이 들어가지 않고 있습니다. 그 외에도 pecl 이나 pear 의 icu library 관련 패키지들에도 이상하게 이 부분만 들어가지 않고 있군요.
그리고 좀 더 안습인 것은, Mozilla 의 Universal Chardet 의 경우에는 C#, java, python, ruby (python chardet 을 porting 했음) 등등이 지원하고 있음에도 불구하고, PHP 나 별도의 c/c++ library 로는 제공되지 않고 있습니다.
Mozilla Universal Charset
Nchardet for C#
jchardet for Java
chardet for python
rchardet for ruby (python clone
Encode-Detect-1.01 > Encode::Detect::Detector for perl
mozilla code 에 c++ 로 지원하고 있으니 이걸 포팅하면 되겠지 하고 쉽게 생각을 했는데, xpcom 구조를 알기 전에는 쉽게 뗄 수 있을 놈이 아니더군요.
이렇듯 저렇듯.. 나오기만 2여년을 기다리다가.. 귀찮아서 mod_chardet 이라는 php extension 으로 하나 만들어 보고 말았습니다. 일단 mod_chardet 은 기본은 ICU library 의 Charset detect 기능을 이용하고, 옵션으로 python chardet 이 설치가 되어 있으면 Python C API를 이용하여 python chardet 을 사용할 수 있도록 설계를 했습니다. Mozilla Universal chardet 이 PHP 만 없다는 것도 좀 그렇다는 생각이 들었고..
일단, ICU 와 Universal Chardet 의 성능 비교도 해 볼겸해서 돌려 보았는데, 역시 ICU 보다는 Universal Chardet 이 detect 능력이 좋더군요. 그리고 ICU 에서 detect 할 수 있는 charset 보다 Universal chardet 이 좀 더 많이 지원하는 까닭도 있었고요.
일단,
python chardet homepage 에 있는 자료가 오래된 까닭에 다음의 환경에서 해당 자료를 다시 분석해 보았습니다. 테스트 환경으로는 다음과 같습니다.
Python 2.5
Python Chardet 1.0.1
PHP 5.2.6
ICU library 4.0.1
Python Chardet result:
google.cn {'confidence': 0.98999999999999999, 'encoding': 'GB2312'}
yahoo.jp {'confidence': 0.98999999999999999, 'encoding': 'utf-8'}
amazon.co.jp {'confidence': 1, 'encoding': 'SHIFT_JIS'}
pravda.ru {'confidence': 0.93312187961594417, 'encoding': 'windows-1251'}
auction.co.kr {'confidence': 0.56471064895612277, 'encoding': 'ISO-8859-2'}
haaretz.co.il {'confidence': 0.98999999999999999, 'encoding': 'windows-1255'}
www.nectec.or.th {'confidence': 0.77645629965698426, 'encoding': 'TIS-620'}
feedparser.org {'confidence': 0.98999999999999999, 'encoding': 'utf-8'}
python-chardet 1.0.1 의 경우, 홈페이지 자료와는 약간 다른 결과가 나오더군요. 일단
python chardet homepage 의 정보가 변경이 되었을 수도 있고, chardet 이 업데이트 되면서 결과가 달라질 수도 있겠지만, 일단 이 결과에서 auction 이 예전에는 제대로 EUC-KR로 판단이 되었는데, 지금 환경에서는 다른 결과를 보여 주고 있습니다.
다음은 mod_chardet 의 결과 입니다.
PHP mod_chardet result:
google.cn (7121)
ICU : Encoding -> GB18030 Confidence -> 100
MOZ : Encoding -> GB2312 Confidence -> 98
yahoo.jp (30367)
ICU : Encoding -> UTF-8 Confidence -> 100
MOZ : Encoding -> utf-8 Confidence -> 98
amazon.co.jp (166082)
ICU : Encoding -> Shift_JIS Confidence -> 100
MOZ : Encoding -> SHIFT_JIS Confidence -> 100
pravda.ru (97826)
ICU : Encoding -> ISO-8859-1 Confidence -> 28
MOZ : Encoding -> windows-1251 Confidence -> 93
auction.co.kr (101330)
ICU : Encoding -> EUC-KR Confidence -> 100
MOZ : Encoding -> ISO-8859-2 Confidence -> 56
haaretz.co.il (174179)
ICU : Encoding -> ISO-8859-1 Confidence -> 32
MOZ : Encoding -> windows-1255 Confidence -> 98
www.nectec.or.th (41527)
ICU : Encoding -> ISO-8859-1 Confidence -> 37
MOZ : Encoding -> TIS-620 Confidence -> 77
feedparser.org (28443)
ICU : Encoding -> UTF-8 Confidence -> 100
MOZ : Encoding -> utf-8 Confidence -> 98
18.33 Sec
보시다 시피, CJK / UTF-8 / ASCII 를 제외한 다른 1byte 권의 언어들에 대해서는 Universal chardet 이 ICU chardet 보다 월등히 detecting 을 잘 하고 있습니다. 다만 안습인 것은, mod_charset 의 Universal chardet 이 Python C API 를 이용해서 python 을 호출하다 보니, ICU 보다 성능이 굉장히 많이 떨어집니다. 실제로 위의 결과를 Universal chadet 체크를 하지 않는다면, 대략 0.04초 정도에 결과가 나옵니디만, Universal chardet detecting 을 시키니 거의 20초 가까운 결과치가 나옵니다.
대략 테스트를 해 보니 문자열이 3K 정도가 넘어가면 Python C API 로 호출한 결과가 상당히 늦어지는 결과를 보이더군요. 대략 1K 이내의 경우에 어느정도 비슷한 속도가 나옵니다.
또한, 짧은 문자열에 대해서도 ICU 보다 Universal chardet 이 성능이 조금 더 좋더군요. 그래도 한글 기준으로 테스트를 했을 때, 한글 10글자 정도는 받아야지 왠만한 confidence 가 나오게 됩니다.
다음의 결과는 web page 에서 html code 를 삭제하고 나온 결과 입니다. 다음의 코드가 사용이 되었습니다.
$buf = preg_replace ('/<[^>]*>/', '', $buf);
보통 웹 페이지의 경우, <>로 쌓여져 있는 코드들은 대부분 ASCII 이기 때문에 확률적 판단을 하는 chardet 에 부정적인 영향을 줄것이라 생각을 하고 한번 시도를 해 보았습니다.
PHP mod_chardet result:
google.cn (2781)
ICU : Encoding -> GB18030 Confidence -> 100
MOZ : Encoding -> GB2312 Confidence -> 98
yahoo.jp (3561)
ICU : Encoding -> UTF-8 Confidence -> 100
MOZ : Encoding -> utf-8 Confidence -> 98
amazon.co.jp (30739)
ICU : Encoding -> Shift_JIS Confidence -> 100
MOZ : Encoding -> SHIFT_JIS Confidence -> 100
pravda.ru (15728)
ICU : Encoding -> windows-1251 Confidence -> 28
MOZ : Encoding -> windows-1251 Confidence -> 94
auction.co.kr (36084)
ICU : Encoding -> EUC-KR Confidence -> 100
MOZ : Encoding -> ISO-8859-2 Confidence -> 27
haaretz.co.il (44570)
ICU : Encoding -> ISO-8859-8-I Confidence -> 23
MOZ : Encoding -> windows-1255 Confidence -> 98
www.nectec.or.th (10425)
ICU : Encoding -> EUC-JP Confidence -> 64
MOZ : Encoding -> TIS-620 Confidence -> 76
feedparser.org (5854)
ICU : Encoding -> UTF-8 Confidence -> 100
MOZ : Encoding -> utf-8 Confidence -> 98
4.86 Sec
이렇게 detecting 을 하니 ICU의 결과가 조금 좋아졌으며 (하지만 오판하는 경우도 생겼군요), 텍스트 양이 줄면서 Python C API를 사용하는 Univiersal chardet 의 성능이 대략 5초 정도로 시간이 절약 되었습니다.
뭐 어쨌든 두가지 기능을 다 지원을 하고, PHP 에서도 Universal chardet 을 지원할 수 있다는 점에 일단은 만족을 하고, posting 과 함께 mod_chardet 을 공개합니다.
그리고 혹시나 단순히 euc-kr / utf-8 만 판단을 해야 한다면, chardet 은 overhead 일 경우가 많습니다. 이럴 경우에는 차라리
pear KSC5601에 있는 is_utf8 method 를 사용하시는 것이 훨씬 경제적/성능적 효과가 좋습니다. 물론 제가 만들어 놓은 것입니다 ^^;
코드는
http://cvs.oops.org/index.php?cvsroot=PHP-Module 에서 받으실 수 있으며, 소스 안의
test.php 를 참조 하시면 사용하시는데 별 무리는 없을 겁니다.
Comments List
관리자만 볼 수 있는 댓글입니다.