Python: Как заменить символы полной ширины на символы полуширины? - PullRequest
10 голосов
/ 11 марта 2010

Если бы это был 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)
}

Я пробовал функцию .translate в python, и это указывает на то, что массивы не одного размера Я предполагаю, что это связано с тем, что отдельные символы закодированы в UTF-8. Какие-либо предложения?

Ответы [ 6 ]

21 голосов
/ 11 марта 2010

Встроенный модуль unicodedata может сделать это:

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

«NFKC» означает « Форма нормализации KC [Декомпозиция совместимости с последующей канонической композицией]» и заменяет символы полной ширины на символы полуширины, которые Unicode эквивалентны 1008 *.

Обратите внимание, что он также одновременно нормализует все виды других вещей, например, отдельные знаки ударения и символы римских цифр.

4 голосов
/ 18 апреля 2016

В 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 и не преобразуют ни одного японского / корейского символа полной ширины.

Для полноты из википедии :

Диапазон U+FF01–FF5E воспроизводит символы от ASCII 21 до 7E в виде формы полной ширины, то есть формы фиксированной ширины, используемые в CJK вычисления. Это полезно для набора латинских символов в CJK среда. U+FF00 не соответствует полной ширине ASCII 20 (пробел), так как эта роль уже выполнена U+3000 "идеографическое пространство".

Диапазон U+FF65–FFDC кодирует формы половинной ширины катакана и хангыль символы.

Диапазон U+FFE0–FFEE включает символы полной и половинной ширины.

И более, решение python2 может относиться к gist / jcayzac

3 голосов
/ 11 марта 2010

Regex подход

>>> import re
>>> re.sub(u"[\uff10-\uff19]",lambda x:chr(ord(x.group(0))-0xfee0),u"456")
u'456'
3 голосов
/ 11 марта 2010

Использование метода unicode.translate:

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

Требуется сопоставление кодовых точек как чисел , а не символов. Кроме того, использование u'unicode literals' оставляет значения незакодированными.

3 голосов
/ 11 марта 2010

Не думаю, что есть встроенная функция для выполнения нескольких замен за один проход, поэтому вам придется сделать это самостоятельно.

Один из способов сделать это:

>>> 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'
1 голос
/ 03 июля 2014

В Python 3 самым чистым является использование str.translate и str.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 и не работает с символами Юникода, поэтому вам нужно создать словарь, как отмечает Джош Ли выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...