由使用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之間,簡略地使用這個範圍便足以滿足我們的需求。
參考資料
附程式碼
# -*-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)