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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值