Удаление непечатаемых символов из строки в python

Я использую для запуска

$s =~ s/[^[:print:]]//g;

на Perl, чтобы избавиться от непечатаемых символов.

В Python нет классов регулярных выражений POSIX, и я не могу написать [: print:], имея в виду то, что я хочу. Я не знаю никого в Python, чтобы определить, печатается ли персонаж или нет.

Что бы вы сделали?

EDIT: он также должен поддерживать символы Unicode. Строковый. Печатный способ будет с радостью вытеснять их из вывода. curses.ascii.isprint вернет false для любого символа юникода.

Ответ 1

Итерация по строкам, к сожалению, довольно медленная в Python. Регулярные выражения на порядок быстрее для такого рода вещей. Вам просто нужно создать класс персонажа самостоятельно. Для этого очень полезен модуль unicodedata, особенно функция unicodedata.category(). Для описания категорий см. Unicode Character Database.

import unicodedata, re

all_chars = (unichr(i) for i in xrange(0x110000))
control_chars = ''.join(c for c in all_chars if unicodedata.category(c) == 'Cc')
# or equivalently and much more efficiently
control_chars = ''.join(map(unichr, range(0,32) + range(127,160)))

control_char_re = re.compile('[%s]' % re.escape(control_chars))

def remove_control_chars(s):
    return control_char_re.sub('', s)

Ответ 2

Насколько я знаю, самый питонический/эффективный метод:

import string

filtered_string = filter(lambda x: x in string.printable, myStr)

Ответ 3

Вы можете попробовать настроить фильтр с помощью функции 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 для доступных категорий.

Ответ 4

В Python 3,

def filter_nonprintable(text):
    import string
    # Get the difference of all ASCII characters from the set of printable characters
    nonprintable = set([chr(i) for i in range(128)]).difference(string.printable)
    # Use translate to remove all non-printable characters
    return text.translate({ord(character):None for character in nonprintable})

См. fooobar.com/questions/17570/... для того, как .translate() сравнивается с regex и .replace()

Ответ 5

Эта функция использует списки и str.join, поэтому она работает в линейном времени вместо O (n ^ 2):

from curses.ascii import isprint

def printable(input):
    return ''.join(char for char in input if isprint(char))

Ответ 6

Лучшее, что я придумал сейчас (благодаря вышеперечисленным питонщикам)

def filter_non_printable(str):
  return ''.join([c for c in str if ord(c) > 31 or ord(c) == 9])

Это единственный способ узнать, что работает с символами/строками Unicode

Любые лучшие варианты?

Ответ 7

В Python нет классов регулярных выражений POSIX

Есть при использовании библиотеки regex: https://pypi.org/project/regex/

Он хорошо поддерживается и поддерживает регулярные выражения Unicode, регулярные выражения Posix и многие другие. Использование (сигнатуры методов) очень похоже на Python re.

Из документации:

[[:alpha:]]; [[:^alpha:]]

Классы символов POSIX поддерживаются. Обычно они рассматриваются как альтернативная форма \p{...}.

(Я не аффилирован, просто пользователь.)

Ответ 8

Один ниже работает быстрее, чем другие выше. Взглянуть

''.join([x if x in string.printable else '' for x in Str])

Ответ 9

Чтобы удалить пробелы,

import re
t = """
\n\t<p>&nbsp;</p>\n\t<p>&nbsp;</p>\n\t<p>&nbsp;</p>\n\t<p>&nbsp;</p>\n\t<p>
"""
pat = re.compile(r'[\t\n]')
print(pat.sub("", t))

Ответ 10

Следующее будет работать с вводом 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.

Ответ 11

Еще один вариант в Python 3:

re.sub(f'[^{re.escape(string.printable)}]', '', my_string)