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

问题描述 投票:0回答:7

如果这是 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 编码的。 有什么建议吗?

python unicode translation
7个回答
39
投票

内置的

unicodedata
模块可以做到:

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

“NFKC”代表“Normalization Form KC [兼容性分解,后跟规范组合]”,用半角字符替换全角字符,这与 Unicode 等效

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


12
投票

在Python3中,您可以使用以下代码片段。它在所有 ASCII 字符和相应的全角字符之间建立映射。最重要的是,这不需要您对 ascii 序列进行硬编码,这很容易出错。

 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)

同样的逻辑,你可以将半角字符转换为全角字符,代码如下:

 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 字符,并且不转换任何日文/韩文全角字符。

为了完整起见,来自wikipedia

范围

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

范围

U+FF65–FFDC
编码片假名和韩文的半角形式 角色。

范围

U+FFE0–FFEE
包括全角和半角符号。

可以在 gist/jcayzac 找到 python2 解决方案。


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
投票

使用

unicode.translate
方法:

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

它需要将代码点映射为数字,而不是字符。此外,使用

u'unicode literals'
会使值保持未编码状态。


3
投票

在 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 上面所述。


3
投票

正则表达式方法

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

0
投票

基于@greenqy的回答链接

在将中文全角标点转换为半角标点时,有些半角标点需要加一个空格看起来更好!

相当不错的解决方案如下,并在

.,!?;:

后面添加一个空格
FULL2HALF_DICT = dict((i + 65248, (chr(i) + ' ' if chr(i) in '.,!?;:' else chr(i))) for i in range(33, 126))
FULL2HALF_DICT[12288] = 32  # full-width space


def full_to_half_width(s):
    """ https://stackoverflow.com/a/36693548/6494418 """
    return str(s).translate(FULL2HALF_DICT)

糟糕的解决方案会导致与浮点数字混淆

def full_to_half_width_no_good(text):
    """Replace full-width punctuation with half-width equivalents.
    这里还是不对, 因为像浮点小数会出现问题, 最好还是在替换时添加空格, 才是正确的.
        https://stackoverflow.com/a/2422245/6494418
        https://stackoverflow.com/a/36693548/6494418
        https://stackoverflow.com/a/44263500/6494418
    """
    import unicodedata
    text = unicodedata.normalize('NFKC', text)  # full_to_half_width
    text = re.sub(r'([.,!?;:])(\S)', r'\1 \2', text)  # add_space_after_punctuation
    return text
© www.soinside.com 2019 - 2024. All rights reserved.