由使用Python2引發的編碼問題的學習記錄

前言

最近接了做字幕的兼職,自己總結了一套效率比較高的流程,但其中有一步需要將混在一起的中文行和英文行分開,所以想到了藉助Python腳本來解決。

本來覺得是個沒那麼複雜的問題,就是檢測某一行是否包括中文即可,不過由於對編碼問題的不熟悉,花了不少功夫。

(建議大家儘快轉用Python3,此類問題會少很多。。。)

正文

編碼溯源

1.爲了處理英文字符,產生了ASCII碼。 
2.爲了處理中文字符,產生了GB2312。 
3.爲了處理各國字符,產生了Unicode。注意Unicode 只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。 
4.爲了提高Unicode存儲和傳輸性能,產生了UTF-8,它是Unicode的一種實現形式。

UTF-8與BOM

Windows下使用UTF-8編碼默認會在文件頭加BOM(byte order mark),它是爲 UTF-16 和 UTF-32 準備的,用於標記字節序(byte order)。

儘管 Unicode 標準允許在 UTF-8 中使用 BOM,但它並不是必要的。特別地,UTF-8 的網頁代碼不應使用 BOM。

微軟在 UTF-8 中使用 BOM 是因爲這樣可以把 UTF-8 和 ASCII 等編碼明確區分開,但這樣的文件在 Windows 之外的操作系統裏會帶來問題。

而使用Notepad++可以將文本文件的編碼格式轉換爲無BOM的UFT-8編碼格式。

系統編碼

系統的默認編碼有所不同(這裏指控制檯顯示的編碼):Linux默認UTF-8,Windows(簡體中文)默認GB2312。

因此直接用Windows控制檯輸出UTF-8編碼格式的中文會出現亂碼,就是因爲編譯碼方式不同,導致解析錯誤。

源碼中的編碼

Python2會將整個python腳本中的內容當做ASCII碼去處理,因此在文件頭部加入一行編碼聲明如:

# -*-coding:utf8-*-

這樣,Python在處理這個腳本時,會用UTF-8的編碼去處理整個腳本,就能夠正確的解析中文字符了。

字符串中的編碼

Python2中的字符串有str和Unicode兩種類型。

str類型的字符串都有一定的編碼方式,如ASCII、GBK、UTF-8等等,而Unicode即爲無編碼格式的計算機存儲符號。

通過encode和decode函數可以在兩者間進行轉換

可以觀察到UNICODE編碼的串輸出時在整個字符串前帶一個'u'的前綴,每個UNICODE符也各自含有一個'\u'的開頭。

查資料知基本漢字的UNICODE範圍在4E00-9FA5之間,簡略地使用這個範圍便足以滿足我們的需求。

參考資料

字符編碼筆記:ASCII,Unicode 和 UTF-8(強烈推薦)

徹底搞懂Python的字符編碼

Window 編碼 UTF-8 BOM 說明

附代碼

# -*-coding:utf8-*-

#首先需將中英文字幕文件編碼格式修改爲UFT-8無BOM編碼格式,並將其放置在所確定的路徑
#轉換結束後再將文件修改回UFT-8編碼格式,或者不轉好像也行 ^_^

def have_Chinese(word):
    for ch in word.decode('utf-8'):
        if u'\u4e00' <= ch <= u'\u9fff':
            return True
    return False
#路徑修改爲翻譯字幕所在路徑
path = "D:\\Desktop\\"
#翻譯字幕文件名
file = path+"Subtitles.txt"
#視頻題目
title = path+"Video"
with open(file,'r') as f:
    lines = f.readlines()
    Cn=[]
    Eng=[]
    for line in lines:
        if len(line) <= 8:  #這意味着空碼,包含時間碼和換行符
            Cn.append(line)
            Eng.append(line)
            continue
        if have_Chinese(line):  #行內包含中文則視爲中文字幕
            Cn.append(line)
        else:
            Eng.append(line)  #否則爲英文字幕
            
with open(title+'.txt','w') as res_Eng:
    for line in Eng:
        res_Eng.write(line)


with open(title+'_CN.txt','w') as res_Cn:
    for line in Cn:
        res_Cn.write(line)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章