Подтвердить что ты не робот

Латинский-1 до ascii

У меня есть строка юникода с акцентированными латинскими символами, например.

n=unicode('Wikipédia, le projet d’encyclopédie','utf-8')

Я хочу преобразовать его в обычный ascii, т.е. "Википедия, le projet dencyclopedie", поэтому все острые/акцент, cedilla и т.д. должны быть удалены.

Каков самый быстрый способ сделать это, поскольку это необходимо сделать для сопоставления выпадающего списка длинной автозаполнения

Вывод: Поскольку одним из моих критериев является скорость, Lennart 'регистрирует собственный обработчик ошибок для кодирования/декодирования Unicode' дает лучший результат (см. Ответ Alex), разность скоростей увеличивается, поскольку все больше и больше символов латинские.

Вот таблица перевода, которую я использую, также модифицированный обработчик ошибок, так как ему нужно позаботиться обо всем диапазоне некодированных char от error.start до error.end

# -*- coding: utf-8 -*-
import codecs

"""
This is more of visual translation also avoiding multiple char translation
e.g. £ may be written as {pound}
"""
latin_dict = {
u"¡": u"!", u"¢": u"c", u"£": u"L", u"¤": u"o", u"¥": u"Y",
u"¦": u"|", u"§": u"S", u"¨": u"`", u"©": u"c", u"ª": u"a",
u"«": u"<<", u"¬": u"-", u"­": u"-", u"®": u"R", u"¯": u"-",
u"°": u"o", u"±": u"+-", u"²": u"2", u"³": u"3", u"´": u"'",
u"µ": u"u", u"¶": u"P", u"·": u".", u"¸": u",", u"¹": u"1",
u"º": u"o", u"»": u">>", u"¼": u"1/4", u"½": u"1/2", u"¾": u"3/4",
u"¿": u"?", u"À": u"A", u"Á": u"A", u"Â": u"A", u"Ã": u"A",
u"Ä": u"A", u"Å": u"A", u"Æ": u"Ae", u"Ç": u"C", u"È": u"E",
u"É": u"E", u"Ê": u"E", u"Ë": u"E", u"Ì": u"I", u"Í": u"I",
u"Î": u"I", u"Ï": u"I", u"Ð": u"D", u"Ñ": u"N", u"Ò": u"O",
u"Ó": u"O", u"Ô": u"O", u"Õ": u"O", u"Ö": u"O", u"×": u"*",
u"Ø": u"O", u"Ù": u"U", u"Ú": u"U", u"Û": u"U", u"Ü": u"U",
u"Ý": u"Y", u"Þ": u"p", u"ß": u"b", u"à": u"a", u"á": u"a",
u"â": u"a", u"ã": u"a", u"ä": u"a", u"å": u"a", u"æ": u"ae",
u"ç": u"c", u"è": u"e", u"é": u"e", u"ê": u"e", u"ë": u"e",
u"ì": u"i", u"í": u"i", u"î": u"i", u"ï": u"i", u"ð": u"d",
u"ñ": u"n", u"ò": u"o", u"ó": u"o", u"ô": u"o", u"õ": u"o",
u"ö": u"o", u"÷": u"/", u"ø": u"o", u"ù": u"u", u"ú": u"u",
u"û": u"u", u"ü": u"u", u"ý": u"y", u"þ": u"p", u"ÿ": u"y", 
u"’":u"'"}

def latin2ascii(error):
    """
    error is  protion of text from start to end, we just convert first
    hence return error.start+1 instead of error.end
    """
    return latin_dict[error.object[error.start]], error.start+1

codecs.register_error('latin2ascii', latin2ascii)

if __name__ == "__main__":
    x = u"¼ éíñ§ÐÌëÑ » ¼ ö ® © ’"
    print x
    print x.encode('ascii', 'latin2ascii')

Почему я возвращаю error.start + 1:

возвращаемый объект ошибки может быть несколькими символами, и мы конвертируем только первый из них, например. если я добавлю print error.start, error.end в вывод обработчика ошибок,

¼ éíñ§ÐÌëÑ » ¼ ö ® © ’
0 1
2 10
3 10
4 10
5 10
6 10
7 10
8 10
9 10
11 12
13 14
15 16
17 18
19 20
21 22
1/4 einSDIeN >> 1/4 o R c '

поэтому во второй строке мы получаем символы из 2-10, но мы конвертируем только 2-й, а затем возвращаем 3 в качестве точки продолжения, если мы возвращаем вывод error.end

¼ éíñ§ÐÌëÑ » ¼ ö ® © ’
0 1
2 10
11 12
13 14
15 16
17 18
19 20
21 22
1/4 e >> 1/4 o R c '

Как мы видим, 2-10 часть была заменена одним char. вне курса, было бы быстрее просто кодировать весь диапазон за один раз и возвращать error.end, но для демонстрационной цели я сохранил это просто.

см. http://docs.python.org/library/codecs.html#codecs.register_error для более подробной информации

4b9b3361

Ответ 1

Итак, вот три подхода, более или менее заданные или предлагаемые в других ответах:

# -*- coding: utf-8 -*-
import codecs
import unicodedata

x = u"Wikipédia, le projet d’encyclopédie"

xtd = {ord(u'’'): u"'", ord(u'é'): u'e', }

def asciify(error):
    return xtd[ord(error.object[error.start])], error.end

codecs.register_error('asciify', asciify)

def ae():
  return x.encode('ascii', 'asciify')

def ud():
  return unicodedata.normalize('NFKD', x).encode('ASCII', 'ignore')

def tr():
  return x.translate(xtd)

if __name__ == '__main__':
  print 'or:', x
  print 'ae:', ae()
  print 'ud:', ud()
  print 'tr:', tr()

Запуск как основной, это испускает:

or: Wikipédia, le projet d’encyclopédie
ae: Wikipedia, le projet d'encyclopedie
ud: Wikipedia, le projet dencyclopedie
tr: Wikipedia, le projet d'encyclopedie

ясно показывает, что подход на основе уникодатной информации, в то время как у него есть удобство, не нуждающееся в карте перевода xtd, не может автоматически переводить все символы автоматически (это работает для букв с акцентом, но не для обратного -apostrophe), поэтому ему также понадобится некоторый вспомогательный шаг для непосредственного решения этих проблем (без сомнения, перед тем, что теперь его тело).

Производительность также интересна. На моем ноутбуке с Mac OS X 10.5 и системой Python 2.5 вполне можно повторить:

$ python -mtimeit -s'import a' 'a.ae()'
100000 loops, best of 3: 7.5 usec per loop
$ python -mtimeit -s'import a' 'a.ud()'
100000 loops, best of 3: 3.66 usec per loop
$ python -mtimeit -s'import a' 'a.tr()'
10000 loops, best of 3: 21.4 usec per loop

translate является неожиданно медленным (относительно других подходов). Я считаю, что проблема заключается в том, что dict учитывается для каждого символа в случае translate (и большинство из них не существует), но только для тех немногих символов, которые имеют ARE с подходом asciify.

Итак, для полноты здесь "усиленный unicodedata" подход:

specstd = {ord(u'’'): u"'", }
def specials(error):
  return specstd.get(ord(error.object[error.start]), u''), error.end
codecs.register_error('specials', specials)

def bu():
  return unicodedata.normalize('NFKD', x).encode('ASCII', 'specials')

это дает правильный выход, НО:

$ python -mtimeit -s'import a' 'a.bu()'
100000 loops, best of 3: 10.7 usec per loop

... скорость уже не так хороша. Итак, если скорость имеет значение, то, без сомнения, стоит задача сделать полный перевод xtd dict и использовать подход asciify. Когда несколько лишних микросекунд на перевод не имеют большого значения, можно подумать о подходе bu просто для его удобства (нужен только перевод, для которого, надеюсь, мало, специальные символы, которые не переводят правильно с основополагающей идеей unicodedata).

Ответ 2

"Правильный" способ сделать это - зарегистрировать свой собственный обработчик ошибок для кодирования/декодирования Unicode, а в этом обработчике ошибок предусмотрены замены от è до e и ö до o и т.д.

Так же:

# -*- coding: UTF-8 -*-
import codecs

map = {u'é': u'e',
       u'’': u"'",
       # ETC
       }

def asciify(error):
    return map[error.object[error.start]], error.end

codecs.register_error('asciify', asciify)

test = u'Wikipédia, le projet d’encyclopédie'
print test.encode('ascii', 'asciify')

Вы также можете найти что-то в библиотеке IBM ICU и это привязки Python PyICU, тем не менее, это может быть меньше.

Ответ 3

Удивительный unidecode модуль делает это для вас:

>>> import unidecode
>>> n = unicode('Wikipédia, le projet d’encyclopédie','utf-8')
>>> unidecode.unidecode(n)
"Wikipedia, le projet d'encyclopedie"

Ответ 4

Maketrans (и переведите), затем преобразуйте в ascii:

intab = u'áéí'  # extend as needed
outtab = u'aei' # as well as this one
table = maketrans(intab, outtab)

text = translate(u"Wikipédia, le projet d’encyclopédie", table)

try:
    temp = unicode(text, "utf-8")
    fixed = unicodedata.normalize('NFKD', temp).encode('ASCII', action)
    return fixed
except Exception, errorInfo:
    print errorInfo
    print "Unable to convert the Unicode characters to xml character entities"
    raise errorInfo

(из здесь)

Ответ 5

Без измерения я ожидал бы, что метод .translate строк Unicode является самым быстрым решением. Однако вы должны сделать свои собственные измерения.

Ответ 6

Пакет unihandecode -

Транслитерация US-ASCII текста Юникода.
улучшенная версия Unidecode Python, то есть порт Python модуля Text:: Unidecode Perl от Шона М. Берка.

pip install Unihandecode

то в python

import unihandecode
print(unihandecode.unidecode(u'Wikipédia, le projet d’encyclopédie'))

выводит Wikipedia, le projet d'encyclopedie.