List non utf-8 encoded files
Arlo 問我有沒有辦法讓 Editplus 2 預設使用 UTF-8 encoding?很可惜地,雖然 Editplus 2 可以預設檔案的行尾要用 PC (CR-LF)、UNIX (LF) 還是 Mac (CR) 格式,但卻沒有辦法預設新檔案要使用的 encoding,一律使用 ANSI codepage。
Arlo 問這個問題,想必是因為常常忘了把原始碼檔案的 encoding 設成 UTF-8,導致程式執行時出錯。我以前也有碰過這樣的困擾,於是從某 trac 資料庫裡把下面這段挖出來:
Here's a command to check which file has incorrect utf8 encoding:
SHELL> find . -type f -name '*.php' -or -name '*.html' -or -name '*.htm' \ | xargs -n 1 -t iconv -f UTF-8 > /dev/nullIf there's any file showing as follows, this file is non-utf8 encoded:
iconv: ./manage_categories.php: cannot convert
想了一想,還是寫成 script 放進 ADE 好了,程式碼是我最佳的知識儲存方法。可以有的變化有:
- 指定要檢查哪些延伸檔名的檔案。以上例來說,就是只檢查
.php、.html或.htm的檔案。 - 可以選擇是否要略過 CVS 或 Subversion 的 working copy 用 meta 目錄。對 CVS working copy 來說,就是
CVS/目錄,對 Subversion working copy 來說,就是.svn/目錄。當然預設是都要略過。
本來還想要寫成可以任意指定要檢查的 encoding。但因為我是用 iconv 轉換作為檢查的方法。若 iconv 可以將成功地該檔自 UTF-8 轉換成目前 locale 指定的 encoding,則是該檔為正確的 UTF-8 檔案。
這裡的關鍵在於 UTF-8 是 unicode,理論上 unicode 包容萬物,可以轉換到任何一種 encoding,所以跑起來沒問題。但若是遇上非 unicode 的 encoding,比如說 GB2312,就沒辦法保證一定能夠轉換成目前 locale 指定的 encoding,而產生一堆 false positive 了。
當然,我還是可以山不轉路轉,改試著從該 encoding 轉換成 unicode,但,算了,懶了,就檢查 UTF-8 就好,以後有需要再說。
於是,有了如下的 usage 設計:
Usage: list_non_utf8.sh [ <option> ... ] <directory> [ <file-ext> ... ] List all non-utf8 encoded files recursively for those files with file extension <file-ext>. Options: -h/--help Show this help message. --no-svn Skip subversion directories. (default) --with-svn Do not skip subversion directories. --no-cvs Skip CVS directories. (default) --with-cvs Do not skip CVS directories.
執行起來應該像這個樣子:
SHELL> list_non_utf8.sh . sh ./taipeilink-with_backup.sh ./bbsclient.sh ./taipeilink.sh
程式很好寫,除了一個「redirection 與 pipeline 處理」的問題:怎樣拋棄 iconv 的 stdout,把 stderr 撿起來 pipe 給另外一個程式處理?因為 iconv 會把轉換後的檔案丟到 stdout,這個是我們不需要的,要轉到 /dev/null 丟棄。而當 iconv 無法成功轉換檔案時,就會在 stderr 上吐出含有檔名的錯誤訊息,而這個檔名,就是我們所需要的。所以我希望達到這個效果:stdout 出來的東西轉到 /dev/null 丟棄,然後 stderr 出來的東西轉給 sed 把非檔名的部分去掉,然後輸出到 stdout。
自己測了半天,寫不出來。寫 shell script 最麻煩的就是 redirection + pipeline 與 quoting + escaption 的問題了。最後拜了一下咕狗大神後找到這個網頁:《KSB's sh redirection and pipeline notes》,聖經啊!在詳細的解說之下,終於用下面的方法解決了我的問題:
iconv -f UTF-8 2>&1 > /dev/null | sed -e ...
所以,雖然 Editplus 2 沒有辦法預設新檔案要使用的 encoding,防止原始碼檔案 encoding 設錯的問題,但我們可以事後用這個 list_non_utf8.sh,檢查出非 UTF-8 編碼的原始碼檔案。UNIX 環境果然才是王道啊,需要什麼非現成的功能,隨時都可以拼拼湊湊兜一個出來用。
Update 2005-10-27
剛剛順便逛了一下 Editplus 2 網站,結果發現新的 2.20 版,剛加上了 Arlo 要的功能,另外還有等很久的「Supports multiple languages in single Unicode or UTF-8 file」的功能,真是不錯。約五年前我就開始在用 Editplus 2 了。Editplus 2 是一個從以前就一直比 UltraEdit 功能還要強大好用的 editor,雖然改版緩慢,但沒有什麼缺憾的合理設計,一直是我的最愛之一。
Update 2008-04-24
還是把 list_non_utf8.sh 列在下面好了:
#!/bin/sh
usage()
{
echo "Usage: list_non_utf8.sh [ <option> ... ] <directory> [ <file-ext> ... ]";
echo "";
echo "List all non-utf8 encoded files recursively for those files with file extension";
echo "<file-ext>.";
echo;
echo "Options:";
echo;
echo " -h/--help Show this help message.";
echo " --no-svn Skip subversion directories. (default)";
echo " --with-svn Do not skip subversion directories.";
echo " --no-cvs Skip CVS directories. (default)";
echo " --with-cvs Do not skip CVS directories.";
echo;
exit 0;
}
exit_with_msg()
{
local ex=0;
local msg='';
if [ $# -gt 0 ]; then
ex=$1;
shift;
fi;
if [ $# -gt 0 ]; then
msg="$1";
shift;
fi;
if [ ! -z "$msg" ]; then
echo "ERROR: $msg";
fi;
echo "Type 'list_non_utf8.sh --help' for usage.";
exit $ex;
}
__opt_directory='';
__opt_file_exts='';
__opt_no_svn='yes';
__opt_no_cvs='yes';
while [ $# -gt 0 ]; do
__arg="$1"; shift;
case "$__arg" in
--no-svn)
__opt_no_svn='yes';
;;
--with-svn)
__opt_no_svn='no';
;;
--no-cvs)
__opt_no_cvs='yes';
;;
--with-cvs)
__opt_no_cvs='no';
;;
-h|--help)
usage;
;;
-*) # argument.
exit_with_msg 1 "Invalid option: $__arg";
;;
*)
if [ -z $__directory ]; then
__opt_directory="$__arg";
else
if [ ! -z $__opt_file_exts ]; then
__opt_file_exts="$__opt_file_exts -or ";
fi;
__opt_file_exts="$__opt_file_exts -name '*.$__arg'";
fi;
;;
esac;
done;
if [ -z "$__opt_directory" ]; then
exit_with_msg 1 "Missing <directory>.";
fi;
if [ \( $__opt_no_svn = 'no' \) -a \( $__opt_no_cvs = 'no' \) ]; then
find $__opt_directory -type f $__opt_file_exts \
| xargs -n 1 iconv -f UTF-8 \
2>&1 > /dev/null \
| sed -e 's/^iconv: //' -e 's/: cannot convert$//'
else
__grep_cmd="grep -v ";
if [ $__opt_no_svn = 'yes' ]; then
__grep_cmd="$__grep_cmd -e .svn/";
fi;
if [ $__opt_no_cvs = 'yes' ]; then
__grep_cmd="$__grep_cmd -e CVS/";
fi;
find $__opt_directory -type f $__opt_file_exts \
| $__grep_cmd \
| xargs -n 1 iconv -f UTF-8 \
2>&1 > /dev/null \
| sed -e 's/^iconv: //' -e 's/: cannot convert$//'
fi;
exit 0;
5 Comments
雖然我也是比較喜歡用Editplus,但UltraEdit的功能似乎是比較完整的... :O
ㄟ...我裝了2.2,只找到create file with UTF8,找不到把open file default encoding 設成utf-8耶..不過話說,Supports multiple languages in single Unicode or UTF-8 file真是太讚了,而且這版已經把FTP function補齊了,等好久了阿!
從主選單 -> Document -> Reload As 可以更改 encoding。強制更改成 UTF-8?這不好吧?好歹要「尊重」原來檔案的 encoding 啊。:-p
這就要扯到一件事了, UTF-8裡ANSI 碼是相容的,
也就是說,今天開一個全是英文程式碼的file,就沒法判別是UTF-8還是iso8559
我的目的是,抓出那些用 UTF-8 處理時會出問題的檔案。既然 ASCII 是個 UTF-8 的子集合,純 ASCII 檔案其實也是符合 UTF-8 的規則。所以,沒關係。
之前就靠這招,從快三千個 XML 檔裡找出二十幾個爛掉的檔案。要不然程式幾時爆炸都不知道。
2 Backlinks
[...] KSB’s sh redirection and pipeline notes - 解釋地非常清楚,幫助我解決了《List non utf-8 encoded files》這篇碰到的問題。 [...]
[...] 更新 2005-11-04:我這篇《List non utf-8 encoded files》講的是一樣的事情。 [...]
Post a Comment