Шаг 34.
Python: сборник рецептов.
Строки и текст. Чистка строк

    На этом шаге мы рассмотрим варианты очистки текста от диакретических символов.

Задача

    Некий деятель ввел текст "pýtĥöñ" в форму на вашей веб-странице, и вы хотите как-то почистить эту строку.

Решение

    Проблема чистки текста применяется к широкому спектру задач с использованием парсинга текста и обработки данных. На самом элементарном уровне вы можете использовать простые строковые функции (например, str.upper() и str.lower() для приведения текста к стандартному регистру). Простые замены с использованием str.replace() или re.sub() помогут справиться с удалением или изменением некоторых специфических последовательностей символов. Вы также можете нормализовать текст, используя функцию unicodedata.normalize(), как показано в 31 шаге.

    Однако вы можете захотеть сделать следующий шаг в процессе чистки. Предположим, что вы хотите удалить целые диапазоны символов или диакритические знаки. Для этого вы можете обратиться к методу str.translate(). Предположим, у вас есть вот такая замусоренная строка:

>>> s = 'pýtĥöñ'
>>> s
'pýtĥöñ'
>>> 

    Первый шаг - удалить пробел. Сделаем небольшую таблицу перевода и задействуем translate():

>>> remap = {
	ord('\t'): ' ',
	ord('\f'): ' ',
	ord('\r'): None  # Удален
	}
>>> a = s.translate(remap)
>>> a
'pýtĥöñ is awesome\n'

    Как вы можете увидеть, символы пробелов, такие как \t и \f, были приведены к единой форме. Символ возврата каретки \r был удален.

    Вы можете продолжить идею и создать намного более крупные таблицы перевода. Например, давайте удалим все комбинирующиеся символы:

>>> import unicodedata
>>> import sys
>>> cmb_chrs = dict.fromkeys(c for c in range(sys.maxunicode) 
    if unicodedata.combining(chr(c)))
>>> b = unicodedata.normalize('NFD', a)
>>> b
'pýtĥöñ is awesome\n'
>>> b.translate(cmb_chrs)
'python is awesome\n'
>>> 

    В последнем примере с помощью dict.fromkeys() был создан словарь, отображающий все комбинирующиеся символы Unicode на None.

    Первоначальные вводные данные затем были нормализованы в декомпозированную форму с использованием unicodedata.normalize(). Далее функция translate() применяется для удаления диакритических знаков. Похожие приемы могут быть использованы для удаления символов другого типа (например, управляющих символов).

    Еще один пример - таблица перевода, которая отображает все десятичные цифры Unicode на их эквиваленты в ASCII:

>>> digitmap = {c: ord('0') + unicodedata.digit(chr(c))
	     for c in range(sys.maxunicode)
	         if unicodedata.category(chr(c)) == 'Nd'}
>>> len(digitmap)
630
>>> # Арабские цифры
>>> x = '\u0661\u0662\u0663'
>>> x.translate(digitmap)
'123'
>>> 

    Еще один прием для чистки текста использует функции кодирования и декодирования ввода-вывода. Идея состоит в выполнении некоторой первичной очистки текста, а затем пропускании его через encode() и decode() для срезания символов или изменения. Например:

>>> a
'pýtĥöñ is awesome\n'
>>> b = unicodedata.normalize('NFD', a)
>>> b.encode('ascii', 'ignore').decode('ascii')
'python is awesome\n'
>>> 

    Здесь процесс нормализации разложил исходный текст на символы вместе с отдельными комбинирующимися символами. Последовательное кодирование и декодирование в ASCII просто удаляет все эти символы. Естественно, это сработает только в том случае, если нашей целью было получение ASCII-представления.

Обсуждение

    Большой проблемой с чисткой текста может стать производительность. Общее правило: чем проще обработка, тем быстрее она работает. Для простых замен метод str.replace() часто оказывается самым быстрым способом - даже если вызывать его несколько раз. Например, чтобы вычистить пробелы, вы можете использовать такую программу:

def clean_spaces(s):
    s = s.replace('\r', '') 
    s = s.replace('\t', '') 
    s = s.replace('\f', '') 
    return s

    Если вы попробуете это, то обнаружите, что метод немного быстрее использования translate() или регулярных выражений.

    С другой стороны, метод translate() очень быстр, если вам нужно выполнить любую нетривиальную операцию замены символов на другие символы или удаления символов.

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

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

    На следующем шаге мы рассмотрим выравнивание текстовых строк.




Предыдущий шаг Содержание Следующий шаг