Python:如何用半角字符替换全角字符?

时间:2010-03-11 02:42:09

标签: python unicode translation

如果这是PHP,我可能会这样做:

function no_more_half_widths($string){
  $foo = array('1','2','3','4','5','6','7','8','9','10')
  $bar = array('1','2','3','4','5','6','7','8','9','10')
  return str_replace($foo, $bar, $string)
}

我在python中尝试过.translate函数,它表明数组的大小不同。我认为这是因为各个字符都是用utf-8编码的。有什么建议?

6 个答案:

答案 0 :(得分:21)

内置unicodedata模块可以执行此操作:

>>> import unicodedata
>>> foo = u'1234567890'
>>> unicodedata.normalize('NFKC', foo)
u'1234567890'

“NFKC”代表“Normalization Form KC [兼容性分解,后面是Canonical Composition]”,并用半角宽度替换全角字符,Unicode equivalent

请注意,它还会同时规范各种其他事物,例如单独的重音符号和罗马数字符号。

答案 1 :(得分:4)

在Python3中,您可以使用以下代码段。它在所有ascii字符和相应的全宽字符之间建立了一个映射。最重要的是,这并不需要你硬类型的ascii序列,这很容易出错。

 #! /usr/bin/env python3
 # -*- coding: utf-8 -*-     

 FULL2HALF = dict((i + 0xFEE0, i) for i in range(0x21, 0x7F))
 FULL2HALF[0x3000] = 0x20

 def halfen(s):
     '''
     Convert full-width characters to ASCII counterpart
     '''
     return str(s).translate(FULL2HALF)

此外,使用相同的逻辑,您可以将半角字符转换为全角字符,以下代码显示了诀窍:

 #! /usr/bin/env python3
 # -*- coding: utf-8 -*-

 HALF2FULL = dict((i, i + 0xFEE0) for i in range(0x21, 0x7F))
 HALF2FULL[0x20] = 0x3000

 def fullen(s):
     '''
     Convert all ASCII characters to the full-width counterpart.
     '''
     return str(s).translate(HALF2FULL)

注意:这两个片段仅考虑ascii字符,并且不会转换任何日语/韩语全角字符。

完整性,来自wikepedia

  

范围U+FF01–FF5E将ASCII 21到7E的字符再现为   全宽形式,即CJK中使用的固定宽度形式   计算。这对于在CJK中排版拉丁字符很有用   环境。 U+FF00与全宽ASCII 20不对应   (空格字符),因为U+3000已完成该角色   "表意空间。"

     

范围U+FF65–FFDC编码片假名和韩文的半宽形式   字符。

     

范围U+FFE0–FFEE包括全宽和半宽符号。

此外,python2解决方案可以参考gist/jcayzac

答案 2 :(得分:3)

我不认为有一个内置函数可以在一次传递中进行多次替换,所以你必须自己做。

一种方法:

>>> src = (u'1',u'2',u'3',u'4',u'5',u'6',u'7',u'8',u'9',u'10')
>>> dst = ('1','2','3','4','5','6','7','8','9','0')
>>> string = u'a123'
>>> for i, j in zip(src, dst):
...     string = string.replace(i, j)
... 
>>> string
u'a123'

或使用字典:

>>> trans = {u'1': '1', u'2': '2', u'3': '3', u'4': '4', u'5': '5', u'6': '6', u'7': '7', u'8': '8', u'9': '9', u'0': '0'}
>>> string = u'a123'
>>> for i, j in trans.iteritems():
...     string = string.replace(i, j)
...     
>>> string
u'a123'

或者最后,使用正则表达式(这实际上可能是最快的):

>>> import re
>>> trans = {u'1': '1', u'2': '2', u'3': '3', u'4': '4', u'5': '5', u'6': '6', u'7': '7', u'8': '8', u'9': '9', u'0': '0'}
>>> lookup = re.compile(u'|'.join(trans.keys()), re.UNICODE)
>>> string = u'a123'
>>> lookup.sub(lambda x: trans[x.group()], string)
u'a123'

答案 3 :(得分:3)

使用unicode.translate方法:

>>> table = dict(zip(map(ord,u'0123456789'),map(ord,u'0123456789')))
>>> print u'123'.translate(table)
123

它需要将代码点映射为数字,而不是字符。此外,使用u'unicode literals'会使值未编码。

答案 4 :(得分:3)

正则表达式方法

>>> import re
>>> re.sub(u"[\uff10-\uff19]",lambda x:chr(ord(x.group(0))-0xfee0),u"456")
u'456'

答案 5 :(得分:1)

在Python 3中,最干净的是使用str.translatestr.maketrans

FULLWIDTH_TO_HALFWIDTH = str.maketrans('1234567890',
                                       '1234567890')
def fullwidth_to_halfwidth(s):
    return s.translate(FULLWIDTH_TO_HALFWIDTH)

在Python 2中,str.maketrans是string.maketrans而不是Unicode字符,所以你需要制作一个字典,正如Josh Lee在上面所说的那样。