大量文字檔編碼轉換
由 darkranger 在 週六, 03/05/2016 - 20:25 發表
一座古蹟應該要修繕到什麼程度,有時候還真是個好問題。
話說本站的前一個版本(v5)是由靜態的 HTML 網頁檔所組成,數了一下,總共有 249 支網頁檔位於舊網站的目錄中,而其中絕大多數是採用繁體中文的 Big5 編碼。然而日前 DR 看著看著,突然覺得這些編碼應該要統一成 UTF-8 才是,於是便開始構思應該要怎麼處理才好。
雖然一開始很自然而然就會想到 iconv 這支工具,但隨後很快就會意識到,這項需求實則需要更加精細的功能。它應該要能夠偵測檔案的編碼,而不是僅檢查 <meta> 標籤的 charset 屬性,然後根據偵測結果來決定是否需要執行編碼轉換。除此之外,它也要能夠在轉換後自動修改 charset 屬性。
於是 DR 撰寫了一支 Python 程式,並使用 chardet 模組來做字元編碼的偵測,在 Fedora 23 上可以利用以下指令來安裝該模組:
- sudo dnf install python-chardet python3-chardet
以下程式碼(text_encoding_conversion.py)會讀取同目錄及子目錄下的所有 HTML 檔,若字元編碼為 Big5 就會轉換為 UTF-8,並變更 charset 屬性值:
#!/usr/bin/python # -*- coding: utf-8 -*- import os, sys, re import codecs import chardet EXTENSIONS = (".htm", ".html") FROM_ENCODING = "big5" TO_ENCODING = "utf-8" def get_encoding(fn): raw_file = open(fn, "rb") encoding = chardet.detect(raw_file.read())["encoding"] raw_file.close() return encoding def do_conversion(fn): input_file = codecs.open(fn, "r", FROM_ENCODING) content = input_file.read() input_file.close() if "<meta " not in content: content = content.replace("<head>", "<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\" />" % TO_ENCODING) else: from_charset = re.compile(re.escape("charset=%s" % FROM_ENCODING), re.I) to_charset = "charset=%s" % TO_ENCODING content = re.sub(from_charset, to_charset, content) output_file = codecs.open(fn, "w", TO_ENCODING) output_file.write(content) output_file.close() def text_encoding_conversion(path): total = 0 converted = 0 for dirname, dirnames, filenames in os.walk(path): for fn in filenames: if fn.lower().endswith(EXTENSIONS): total = total + 1 full_path = os.path.join(dirname, fn) encoding = get_encoding(full_path) print("%s - %s" % (encoding, full_path)) if encoding and encoding.lower() == FROM_ENCODING: do_conversion(full_path) converted = converted + 1 print("%d files checked, %d converted." % (total, converted)) if __name__ == "__main__": appdir = os.path.abspath(os.path.dirname(sys.argv[0])) text_encoding_conversion(appdir)