К сожалению, перебор строк в Python выполняется довольно медленно. Регулярные выражения для такого рода вещей более чем на порядок быстрее. Вам просто нужно самому создать класс персонажа. Для этого очень полезен модуль unicodedata , особенно функция unicodedata.category () . См. Описание категорий в базе данных символов Unicode .
import unicodedata, re, itertools, sys
all_chars = (chr(i) for i in range(sys.maxunicode))
categories = {'Cc'}
control_chars = ''.join(c for c in all_chars if unicodedata.category(c) in categories)
control_chars = ''.join(map(chr, itertools.chain(range(0x00,0x20), range(0x7f,0xa0))))
control_char_re = re.compile('[%s]' % re.escape(control_chars))
def remove_control_chars(s):
return control_char_re.sub('', s)
Для Python2
import unicodedata, re, sys
all_chars = (unichr(i) for i in xrange(sys.maxunicode))
categories = {'Cc'}
control_chars = ''.join(c for c in all_chars if unicodedata.category(c) in categories)
control_chars = ''.join(map(unichr, range(0x00,0x20) + range(0x7f,0xa0)))
control_char_re = re.compile('[%s]' % re.escape(control_chars))
def remove_control_chars(s):
return control_char_re.sub('', s)
Для некоторых случаев использования дополнительные категории (например, все из контрольной группы могут быть предпочтительнее, хотя это может замедлить время обработки и значительно увеличить использование памяти. Количество символов в категории:
Cc
(контроль): 65
Cf
(формат): 161
Cs
(суррогатная мать): 2048
Co
(частное использование): 137468
Cn
(не назначен): 836601
Редактировать Добавление предложений из комментариев.
all_chars = (unichr(i) for i in xrange(sys.maxunicode))
чтобы избежать ошибки узкой сборки.control_chars == '\x00-\x1f\x7f-\x9f'
(проверено на Python 3.5.2)Насколько я знаю, наиболее питоническим / эффективным методом будет:
import string filtered_string = filter(lambda x: x in string.printable, myStr)
источник
Вы можете попробовать настроить фильтр с помощью
unicodedata.category()
функции:import unicodedata printable = {'Lu', 'Ll'} def filter_non_printable(str): return ''.join(c for c in str if unicodedata.category(c) in printable)
См. Таблицу 4-9 на странице 175 в свойствах символов базы данных Unicode для доступных категорий.
источник
printable = {'Lu', 'Ll', Zs', 'Nd'}
В Python 3
def filter_nonprintable(text): import itertools # Use characters of control category nonprintable = itertools.chain(range(0x00,0x20),range(0x7f,0xa0)) # Use translate to remove all non-printable characters return text.translate({character:None for character in nonprintable})
См. Этот пост StackOverflow об удалении знаков препинания, чтобы узнать, как .translate () сравнивается с регулярным выражением и .replace ()
Диапазоны могут быть сгенерированы с
nonprintable = (ord(c) for c in (chr(i) for i in range(sys.maxunicode)) if unicodedata.category(c)=='Cc')
помощью категорий базы данных символов Unicode, как показано @Ants Aasma.источник
text.translate({c:None for c in itertools.chain(range(0x00,0x20),range(0x7f,0xa0))})
.Следующее будет работать с вводом Unicode и довольно быстро ...
import sys # build a table mapping all non-printable characters to None NOPRINT_TRANS_TABLE = { i: None for i in range(0, sys.maxunicode + 1) if not chr(i).isprintable() } def make_printable(s): """Replace non-printable characters in a string.""" # the translate method on str removes characters # that map to None from the string return s.translate(NOPRINT_TRANS_TABLE) assert make_printable('Café') == 'Café' assert make_printable('\x00\x11Hello') == 'Hello' assert make_printable('') == ''
Мое собственное тестирование показывает, что этот подход быстрее, чем функции, которые перебирают строку и возвращают результат с использованием
str.join
.источник
LINE_BREAK_CHARACTERS = set(["\n", "\r"])
иand not chr(i) in LINE_BREAK_CHARACTERS
при построении таблицы.Эта функция использует понимание списка и str.join, поэтому она выполняется за линейное время вместо O (n ^ 2):
from curses.ascii import isprint def printable(input): return ''.join(char for char in input if isprint(char))
источник
filter(isprint,input)
Еще один вариант в Python 3:
re.sub(f'[^{re.escape(string.printable)}]', '', my_string)
источник
r'[^' + re.escape(string.printable) + r']'
. (Я не думаю, чтоre.escape()
здесь полностью правильно, но если этоЛучшее, что я придумал, это (спасибо python-izers выше)
def filter_non_printable(str): return ''.join([c for c in str if ord(c) > 31 or ord(c) == 9])
Это единственный способ, который я обнаружил, который работает с символами / строками Unicode.
Есть варианты лучше?
источник
Один из них работает быстрее, чем остальные. Взглянем
''.join([x if x in string.printable else '' for x in Str])
источник
"".join([c if 0x21<=ord(c) and ord(c)<=0x7e else "" for c in ss])
При использовании
regex
библиотеки есть: https://pypi.org/project/regex/Он хорошо поддерживается и поддерживает регулярные выражения Unicode, регулярные выражения Posix и многие другие. Использование (сигнатуры методов) очень похоже на использование Python
re
.Из документации:
(Я не аффилирован, просто пользователь.)
источник
Основываясь на ответе @Ber, я предлагаю удалить только управляющие символы, как определено в категориях базы данных символов Unicode :
import unicodedata def filter_non_printable(s): return ''.join(c for c in s if not unicodedata.category(c).startswith('C'))
источник
startswith('C')
но в моем тестировании это было гораздо менее эффективным, чем любое другое решение.if unicodedata.category(c)[0] != 'C'
вместо этого. Он работает лучше? Если вы предпочитаете скорость выполнения требованиям к памяти, можно предварительно вычислить таблицу, как показано в stackoverflow.com/a/93029/3779655Чтобы удалить "пробел",
import re t = """ \n\t<p> </p>\n\t<p> </p>\n\t<p> </p>\n\t<p> </p>\n\t<p> """ pat = re.compile(r'[\t\n]') print(pat.sub("", t))
источник
Адаптировано из ответов Антса Аасмы и Шонрада :
nonprintable = set(map(chr, list(range(0,32)) + list(range(127,160)))) ord_dict = {ord(character):None for character in nonprintable} def filter_nonprintable(text): return text.translate(ord_dict) #use str = "this is my string" str = filter_nonprintable(str) print(str)
протестировано на Python 3.7.7
источник