http://hi.baidu.com/netwrom/blog/item/8885f31ef0d09ae7e1fe0b1c.html
在很多类unix平台上都有一个iconv工具,可以用来转换字符编码;而对于普通的文本文件,file命令可以用来检测某个文件的字符编码类型,结合两者就可以非常方便地把一个未知编码类型的文本文件用某一指定编码类型进行编码。 例如,linux内核源代码的某些文件编码就不是用ASCII编码的(貌似跟有些hacker“怪样”的姓名有关),例如: $ cd /path/to/linux-2.6.17 $ file kernel/sys.c kernel/sys.c: ISO-8859 C program text
可见这个文件的字符编码类型是ISO-8859。 看看里头有哪些不是ASCII编码的,用iconv试着从ASCII转一下: $ iconv -f ASCII -t UTF8 kernel/sys.c > /tmp/sys.c iconv: illegal input sequence at position 29203
发现转换出错了,在29203字节位置的字符编码并非是ASCII,用hexdump和cat命令看看该位置到底是什么: $ hexdump -C -n 10 -s 29203 kernel/sys.c 00007213 e5 20 73 76 65 6e 73 6b 61 2e |. svenska.| 0000721d $ cat kernel/sys.c | grep svenska * Samma p? svenska..
估计这个应该是某个作者的名字吧。 下面根据file命令告诉我们的编码类型ISO-8859进行转换,先得通过iconv -l查看iconv到底支持ISO-8859不? $ iconv -l | grep ISO-8859 ISO-8859-1// ISO-8859-2// ISO-8859-3// ISO-8859-4// ISO-8859-5// ISO-8859-6// ISO-8859-7// ISO-8859-8// ISO-8859-9// ISO-8859-9E// ISO-8859-10// ISO-8859-11// ISO-8859-13// ISO-8859-14// ISO-8859-15// ISO-8859-16//
明显支持,但并不直接支持ISO-8859,所以在转换时得选择其中的一个试试。 $ iconv -f ISO-8859-1 -t UTF8 kernel/sys.c > /tmp/sys.c
再看看转换以后的文件大小和29203字节附近的内容: $ ls -l kernel/sys.c /tmp/sys.c -rwxr-xr-x 1 falcon falcon 50359 2006-06-18 09:49 kernel/sys.c -rw-r--r-- 1 falcon falcon 50360 2008-06-29 14:06 /tmp/sys.c $ cat /tmp/sys.c | grep sven * Samma på svenska.. 总结一下:如果想把一个未知字符编码类型的文本文件用指定的编码类型重新编码,该怎么办呢?
1. 用file命令查看该文件的字符编码 2. 通过iconv -l确认iconv是否支持该编码类型,如果支持,从中找出一个最接近的试试 3. 如果可以,那么启用iconv进行转换,否则提示错误
这样就可以写一个脚本来自动进行这个转换过程了(不完善,可以自己添加一些内容),例如:
Code: #!/bin/bash #encode.sh -- encode a file with an indicated encoding
# make sure user give two arguments
[ "$#" != 2 ] && echo "Usage: `basename $0` [to_encoding] [file]" && exit -1
# make sure the second argument is a regular file
[ ! -f $2 ] && echo "the second argument should be a regular file " && exit 1 file=$2
# make sure the first argument is a encoding supported by iconv
iconv -l | grep -q $1 [ $? -ne 0 ] && echo "iconv not support such encoding: $1" && exit -1 to_encoding=$1
# is there a text file? file_type=`file $file | grep "text$"` [ $? -ne 0 ] && echo "$file is not a text file" && exit -1
# get the old encoding from_encoding=`echo $file_type | cut -d" " -f 2` from_encoding=`iconv -l | grep $from_encoding` [ $? -ne 0 ] && echo "iconv not support the old encoding: $from_encoding" from_encoding=`echo $from_encoding | cut -d"/" -f 1`
# convert the file from from_encoding to to_encoding iconv -f $from_encoding -t $to_encoding $file
[Ctrl+A Select All] 下载以后保存为encode.sh,添加可执行权限,并转换一个文件试试。 $ chmod +x encode.sh $ ./encode.sh UTF8 kernel/sys.c
charset-detector:自動偵測文件編碼的小程式 發展程式前,通常會有個動機,而就我剛剛做的這個小程式來說,就是為了透過 [PCManX] 連線到對岸的 BBS 站台,可惜我遇到很麻煩的問題,就是得自己指定編碼,偏偏上週騎腳踏車時,把手握太大力造成輕微受傷,所以一直打錯字... Anyway,我決定要替 [PCManX] 加上自動偵測 BBS 編碼的功能。 自動猜測文件編碼的演算法,在 Mozilla 中已經有不錯的實做,而 Mozilla 官方網頁也提供論文 [A composite approach to language/encoding detection] 作參考,對岸的網友提供了簡體中文翻譯 [一種語言/編碼檢測的復合方法],相關的實做可參考 Mozilla cvs tree [extensions/universalchardet],而之前的 blog [Mozilla Re-licensing 完畢] 也提到 Mozilla Foundation 日前宣佈,Mozilla codebase 由原本的 MPL (Mozilla Public License) 轉換為 MPL / GPL / LGPL 三重授權模式,這與 [PCManX] 的授權相容,所以當務之急就是如何整合。 我初步將 NSPR (Mozilla Runtime) 一類的包袱去掉,並且用 G++ 的 -fno-rtti、-fno-exceptions,以及 -nostdinc++ compilation flags 來編譯 ,如果將 -lstdc++ 換成 -lsupc++,還可進一步得到 C-only library,目標是作成一個 add-on,讓 [PCManX] 可透過 dlopen 來操控內部實做,初步完成自動偵測文件編碼與測試程式,名為 [charset-detector] (bzip2 tarball)。 以下以測試程式 (放在 test 目錄下) 作範例,看看運作情況,initcall.txt 是個用 Big5 編碼的文件: charset-detector/test$ file initcall.txt
initcall.txt: ISO-8859 English text, with CRLF line terminators
charset-detector/test$ ./test-chardetect ./initcall.txt
File ./initcall.txt ...
Charset = Big5
UNIX 的工具 file 就誤判了,還好咱們的 charset-detector 正確識別編碼,而 charset-detect library 的 API 只有六個,很容易操作。下一步就是 hack [PCManX],使其建立 BBS connection 後,將 buffer 傳遞給 charset-detect APIs 作編碼的判斷,稍後作適度的畫面重繪動作。 由 jserv 發表於 May 22, 2006 05:40 PM |