zz使用 Python 分離中文與英文的混合字串

使用 Python 分離中文與英文的混合字串

LiYanrui posted @ 大約 1 年前 in 程序設計 with tags python , 614 閱讀

這個問題是做 MkIV 預處理程序 時搞定的,就是把一個混合了中英文混合字串分離爲英文與中文的子字串,譬如,將 ”我的 English 學的不好 “ 分離爲 “我的"" English ” "學的不好" 三個子字串。

1. 中英文混合字串的統一編碼表示

中英文混合字串處理最省力的辦法就是把它們的編碼都轉成 Unicode,讓一個漢字與一個英文字母的內存位寬都是相等的。這個工作用 Python 來做,比較合適,因爲 Python 內碼採用的是 Unicode,並且爲了支持 Unicode 字串的操作,Python 做了一個 Unicode 內建模塊,把 string 對象的全部方法重新實現了一遍,另外提供了 Codecs 對象,解決各種編碼類型的字符串解碼與編碼問題。

譬如下面的 Python 代碼,可實現 UTF-8 編碼的中英文混合字串向 Unicode 編碼的轉換:

# -*- coding:utf-8 -*-
a = "我的 English 學的不好"
print type ( a) ,len ( a) , a

b = unicode ( a, "utf-8" )
print type ( b) , len ( b) , b

字符串 a 是 utf-8 編碼,使用 python 的內建對象 unicode 可將其轉換爲 Unicode 編碼的字符串 b。上述代碼執行後的輸出結果如下所示,比較字串 a 與字串 b 的長度,顯然 len (b) 的輸出結果是合理的。

<type 'str' > 27 我的 English 學的不好
<type 'unicode' > 15 我的 English 學的不好

要注意的一個問題是 Unicode 雖然號稱是“統一碼”,不過也是存在着兩種形式,即:

  • UCS-2:爲 16 位碼,具有 2^16 = 65536 個碼位;
  • UCS-4:爲 32 位碼,目前的規定是其首字節的首位爲 0,因此具有 2^31 = 2147483648 個碼位,不過現在的只使用了 0x00000000 - 0x0010FFFF 之間的碼位,共 1114112 個。

使用Python  sys 模塊提供的一個變量 maxunicode 的值可以判斷當前 Python 所使用的 Unicode 類型是 UCS-2 的還是 UCS-4 的。

import sys
print sys .maxunicode

若 sys.maxunicode 的值爲 1114111,即爲 UCS-4;若爲 65535,則爲 UCS-2。

2. 中英文混合字串的分離

一旦中英文字串的編碼獲得統一,那麼對它們進行分裂就是很簡單的事情了。首先要爲中文字串與英文字串分別準備一個收集器,使用兩個空的字串對象即 可,譬如 zh_gather 與 en_gather;然後要準備一個列表對象,負責按分離次序存儲 zh_gather 與 en_gather 的值。下面這個 Python 函數接受一箇中英文混合的 Unicode 字串,並返回存儲中英文子字串的列表。

def split_zh_en ( zh_en_str) :

        zh_en_group = [ ]
        zh_gather = ""
        en_gather = ""
        zh_status = False

        for c in zh_en_str:
                if not zh_status and is_zh ( c) :
                        zh_status = True
                        if en_gather != "" :
                                zh_en_group.append ( [ mark[ "en" ] ,en_gather] )
                                en_gather = ""
                elif not is_zh ( c) and zh_status:
                        zh_status = False
                        if zh_gather != "" :
                                zh_en_group.append ( [ mark[ "zh" ] , zh_gather] )
                if zh_status:
                        zh_gather += c
                else :
                        en_gather += c                               
                        zh_gather = ""

        if en_gather != "" :
                zh_en_group.append ( [ mark[ "en" ] ,en_gather] )
        elif zh_gather != "" :
                zh_en_group.append ( [ mark[ "zh" ] ,zh_gather] )

        return zh_en_group

上述代碼所實現的功能細節是:對中英文混合字串 zh_en_str 的遍歷過程中進行逐字識別,若當前字符爲中文,則將其添加到 zh_gather 中;若當前字符爲英文,則將其添加到 en_gather 中。zh_status 表示中英文字符的切換狀態,當 zh_status 的值發生突變時,就將所收集的中文子字串或英文子字串添加到 zh_en_group 中去。

判斷字串 zh_en_str 中是否包含中文字符的條件語句中出現了一個 is_zh () 函數,它的實現如下:

def is_zh ( c) :
        x = ord ( c)
        # Punct & Radicals
        if x >= 0x2e80 and x <= 0x33ff:
                return True

        # Fullwidth Latin Characters
        elif x >= 0xff00 and x <= 0xffef:
                return True

        # CJK Unified Ideographs &
        # CJK Unified Ideographs Extension A
        elif x >= 0x4e00 and x <= 0x9fbb:
                return True
        # CJK Compatibility Ideographs
        elif x >= 0xf900 and x <= 0xfad9:
                return True

        # CJK Unified Ideographs Extension B
        elif x >= 0x20000 and x <= 0x2a6d6:
                return True

        # CJK Compatibility Supplement
        elif x >= 0x2f800 and x <= 0x2fa1d:
                return True

        else :
                return False

這段代碼來自 jjgod 寫的 XeTeX 預處理程序。

對於分離出來的中文子字串與英文子字串,爲了使用方便,在將它們存入 zh_en_group 列表時,我對它們分別做了標記,即 mark["zh"] 與 mark["en"]。mark 是一個 dict 對象,其定義如下:

mark = { "en" :1 , "zh" :2 }

如果要對 zh_en_group 中的英文字串或中文字串進行處理時,標記的意義在於快速判定字串是中文的,還是英文的,譬如:

for str in zh_en_group:
        if str [ 0 ] = mark[ "en" ] :
                do somthing
        else :
                do somthing
發佈了26 篇原創文章 · 獲贊 152 · 訪問量 134萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章