Удаление непечатных символов из строки в Python - PullRequest
80 голосов
/ 18 сентября 2008

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

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

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

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

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

РЕДАКТИРОВАТЬ: он также должен поддерживать символы Unicode. Способ string.printable с радостью удалит их из вывода. curses.ascii.isprint вернет false для любого символа Юникода.

Ответы [ 11 ]

72 голосов
/ 18 сентября 2008

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

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)
62 голосов
/ 18 сентября 2008

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

import string

filtered_string = filter(lambda x: x in string.printable, myStr)
11 голосов
/ 18 сентября 2008

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

9 голосов
/ 14 сентября 2014

В 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})

См. этот пост StackOverflow по удалению пунктуации , чтобы узнать, как .translate () сравнивается с regex & .replace ()

5 голосов
/ 18 сентября 2008

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

from curses.ascii import isprint

def printable(input):
    return ''.join(char for char in input if isprint(char))
2 голосов
/ 05 июля 2018

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

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

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

в Python.

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

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

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

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

2 голосов
/ 18 сентября 2008

Лучшее, что я придумала сейчас (благодаря вышеизложенным python-izers)

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

Это единственный способ, который я обнаружил, который работает с символами / строками Юникода

Есть ли лучшие варианты?

1 голос
/ 07 января 2018

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

''.join([x if x in string.printable else '' for x in Str])
0 голосов
/ 31 января 2019

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

0 голосов
/ 27 сентября 2018

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

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