Что самый быстрый путь состоит в том, чтобы разделить и заменить документ высоких unicode символов с помощью Python?

Я обращаюсь к замене из большого документа все высокие unicode символы, такие как акцентируемый Es, левые и правые кавычки, и т.д., с "нормальными" дубликатами в низком диапазоне, такими как обычный 'E' и прямые кавычки. Я должен выполнить это на очень большом документе скорее часто. Я вижу пример этого в том, что я думаю, мог бы быть жемчуг здесь: http://www.designmeme.com/mtplugins/lowdown.txt

Существует ли быстрый способ сделать это в Python, не используя s.replace (...) .replace (...) .replace (...)...? Я попробовал это всего на нескольких символах для замены, и разделение документа стало действительно медленным.

РЕДАКТИРОВАНИЕ, моя версия кода unutbu, который, кажется, не работает:

# -*- coding: iso-8859-15 -*-
import unidecode
def ascii_map():
    data={}
    for num in range(256):
        h=num
        filename='x{num:02x}'.format(num=num)
        try:
            mod = __import__('unidecode.'+filename,
                             fromlist=True)
        except ImportError:
            pass
        else:
            for l,val in enumerate(mod.data):
                i=h<<8
                i+=l
                if i >= 0x80:
                    data[i]=unicode(val)
    return data

if __name__=='__main__':
    s = u'“fancy“fancy2'
    print(s.translate(ascii_map()))

5
задан Rhubarb 25 May 2010 в 13:21
поделиться

5 ответов

# -*- encoding: utf-8 -*-
import unicodedata

def shoehorn_unicode_into_ascii(s):
    return unicodedata.normalize('NFKD', s).encode('ascii','ignore')

if __name__=='__main__':
    s = u"éèêàùçÇ"
    print(shoehorn_unicode_into_ascii(s))
    # eeeaucC

Обратите внимание: как любезно отмечает @Mark Tolonen, описанный выше метод удаляет некоторые символы, например SS''"". Если в приведенном выше коде усекаются символы, которые вы хотите перевести, возможно, вам придется использовать метод строки translate , чтобы вручную исправить эти проблемы. Другой вариант - использовать unidecode (см. ответ Дж. Ф. Себастьяна ).

Если у вас большая строка в Юникоде, использование ее метода translate будет намного сложнее. намного быстрее, чем при использовании метода replace .

Правка: unidecode имеет более полное отображение кодовых точек Unicode в ascii. Однако unidecode.unidecode перебирает строку посимвольно (в цикле Python), что медленнее, чем при использовании метода translate .

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

В моих тестах с текстовыми файлами размером 1–6 МБ использование ascii_map примерно в 4–6 раз быстрее, чем unidecode.unidecode .

# -*- coding: utf-8 -*-
import unidecode
def ascii_map():
    data={}
    for num in range(256):
        h=num
        filename='x{num:02x}'.format(num=num)
        try:
            mod = __import__('unidecode.'+filename,
                             fromlist=True)
        except ImportError:
            pass
        else:
            for l,val in enumerate(mod.data):
                i=h<<8
                i+=l
                if i >= 0x80:
                    data[i]=unicode(val)
    return data

if __name__=='__main__':
    s = u"éèêàùçÇ"
    print(s.translate(ascii_map()))
    # eeeaucC

Edit2: Rhubarb, если # - * - encoding: utf-8 - * - вызывает SyntaxError, попробуйте # - * - кодировка: cp1252 - * - . Какая кодировка объявляется, зависит от того, какую кодировку использует ваш текстовый редактор для сохранения файла. Linux имеет тенденцию использовать utf-8, и (кажется, возможно) Windows стремится к cp1252.

7
ответ дан 18 December 2019 в 11:54
поделиться

Вот решение, которое обрабатывает символы latin-1 (на основе потока usenet 2003 г.):

>>> accentstable = str.join("", map(chr, range(192))) + "AAAAAAACEEEEIIIIDNOOOOOxOUUUUYTsaaaaaaaceeeeiiiidnooooo/ouuuuyty"
>>> import string
>>> s = u"éèêàùçÇ"
>>> print string.translate(s.encode('latin1', 'ignore'), accentstable)
eeeaucC

Некоторые сопоставления не идеальны, например Thorn сопоставляется с T, а не с Th, но выполняет сносную работу.

0
ответ дан 18 December 2019 в 11:54
поделиться

Не существует такого понятия, как "символ высокого ascii". Набор символов ASCII ограничен порядковым номером в диапазоне (128).

Кроме того, это FAQ.Вот один ответ . В общем, вам следует ознакомиться с str.translate () и unicode.translate () - очень удобно для множественных замен одиночных байтов / символов. Остерегайтесь ответов, в которых упоминается только уловка unicodedata.normalize (); это только одна часть решения.

Обновление : принятый в настоящее время ответ отбрасывает символы, у которых нет разложения, как указал Марк Толонен. Кажется, нам не хватает знаний о том, на что способен unicode.translate () . Он МОЖЕТ переводить один символ в несколько символов. Вот результат help (unicode.translate) :

S.translate (table) -> unicode

Возвращает копию строки S, где все символы были сопоставлены с заданным таблица преобразования, которая должна быть отображением порядковых номеров Unicode в порядковые номера Unicode, строк Unicode или None. Неотмеченные символы остаются нетронутыми. Символы, сопоставленные с параметром «Нет», удаляются.

Вот пример:

>>> u"Gau\xdf".translate({0xdf: u"ss"})
u'Gauss'
>>>

Вот таблица исправлений из решения, на которое я указал:

CHAR_REPLACEMENT = {
    # latin-1 characters that don't have a unicode decomposition
    0xc6: u"AE", # LATIN CAPITAL LETTER AE
    0xd0: u"D",  # LATIN CAPITAL LETTER ETH
    0xd8: u"OE", # LATIN CAPITAL LETTER O WITH STROKE
    0xde: u"Th", # LATIN CAPITAL LETTER THORN
    0xdf: u"ss", # LATIN SMALL LETTER SHARP S
    0xe6: u"ae", # LATIN SMALL LETTER AE
    0xf0: u"d",  # LATIN SMALL LETTER ETH
    0xf8: u"oe", # LATIN SMALL LETTER O WITH STROKE
    0xfe: u"th", # LATIN SMALL LETTER THORN
    }

Это может быть легко расширено, чтобы учесть причудливые кавычки и другие символы, отличные от латинских 1, найденные в cp1252 и братья и сестры.

4
ответ дан 18 December 2019 в 11:54
поделиться

Я считаю, что unicodedata не работает для необычных цитат. В этом случае вы можете использовать Unidecode :

import unidecode
print unidecode.unidecode(u"ß‘’“”")
# -> ss''""
3
ответ дан 18 December 2019 в 11:54
поделиться

Если unicodedata.normalize () , как предлагает ~ unubtu , не помогает, например, если вы хотите больше контролировать отображение вам следует изучить
str.translate ()
вместе с str.maketrans () , утилитой для создания таблицы сопоставления, str.translate одновременно эффективен и удобен для этого типа перевод.
В Python 2.x и для строк Unicode необходимо использовать unicode.translate () вместо str.translate () и трюк, аналогичный показанному в фрагменте кода ниже, вместо maketrans ( ). (спасибо Джону Мачину за указание на это!)

Эти методы также доступны в Python 3.x, см., Например, документацию Python 3.1.2 (по какой-то причине я сделал мысленное замечание, что это могло измениться в Python 3.x). Конечно, в Python 3 все строки являются строками Unicode, но это другая проблема.

#Python 3.1
>>> intab = 'àâçêèéïîôù'
>>> outtab = 'aaceeeiiou'
>>> tmap = str.maketrans(intab, outtab)
>>> s = "à la fête de l'été, où il fait bon danser, les Français font les drôles"
>>> s
"à la fête de l'été, où il fait bon danser, les Français font les drôles"
>>> s.translate(tmap)
"a la fete de l'ete, ou il fait bon danser, les Francais font les droles"
>>>


#Python 2.6
>>> intab = u'àâçêèéïîôù'
>>> outtab = u'aaceeeiiou'
>>> s = u"à la fête de l'été, où il fait bon danser, les Français font les drôles"
>>> #note the trick to replace maketrans() since for unicode strings the translation
>>> #     map expects integers (unicode ordinals) not characters.
>>> tmap = dict(zip(map(ord, intab), map(ord, outtab))) 
>>> s.translate(tmap)
u"a la fete de l'ete, ou il fait bon danser, les Francais font les droles"
>>>
1
ответ дан 18 December 2019 в 11:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: