it-swarm.it

Strippaggio di caratteri non stampabili da una stringa in python

Io uso per correre

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

su Perl per sbarazzarsi di personaggi non stampabili. 

In Python non esistono classi di espressioni regolari POSIX e non riesco a scrivere [: print:] perché significa ciò che voglio. Non conosco alcun modo in Python per rilevare se un personaggio è stampabile o meno. 

Cosa faresti? 

EDIT: deve supportare anche caratteri Unicode. Il modo string.printable li estrae felicemente dall'output. curses.ascii.isprint restituirà false per qualsiasi carattere unicode.

75
Vinko Vrsalovic

L'iterazione su stringhe è sfortunatamente piuttosto lenta in Python. Le espressioni regolari sono più di un ordine di grandezza più veloci per questo genere di cose. Devi solo costruire la classe del personaggio da solo. Il modulo unicodedata è abbastanza utile per questo, specialmente la funzione unicodedata.category (). Vedi Database dei caratteri Unicode per le descrizioni delle categorie.

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)
70
Ants Aasma

Per quanto ne so, il metodo più Pythonic/efficiente sarebbe:

import string

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

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

Vedi questo post StackOverflow sulla rimozione della punteggiatura per come .translate () confronta con regex e .replace ()

9
shawnrad

Potresti provare a impostare un filtro usando la funzione unicodedata.category():

printable = Set('Lu', 'Ll', ...)
def filter_non_printable(str):
  return ''.join(c for c in str if unicodedata.category(c) in printable)

Vedere le proprietà dei caratteri del database Unicode per le categorie disponibili

8
Ber

Questa funzione utilizza le list comprehensions e str.join, quindi viene eseguita in tempo lineare anziché in O (n ^ 2):

from curses.ascii import isprint

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

Il meglio che ho trovato ora è (grazie ai python-izer qui sopra) 

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

Questo è l'unico modo in cui ho scoperto che funziona con caratteri/stringhe Unicode

Qualche opzione migliore?

2
Vinko Vrsalovic

In Python non ci sono classi regex POSIX

Ci sono quando si utilizza la libreria regex: https://pypi.org/project/regex/

È ben gestito e supporta regex Unicode, regex Posix e molti altri. L'utilizzo (firme del metodo) è very simile a re di Python.

Dalla documentazione:

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

Sono supportate le classi di caratteri POSIX. Questi sono normalmente trattati come una forma alternativa di \p{...}.

(Non sono affiliato, solo un utente.)

1
Risadinha

Quello sotto funziona più velocemente degli altri sopra. Guarda

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

Per rimuovere "spazi bianchi",

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))
0
knowingpark

Quanto segue funzionerà con l'input Unicode ed è piuttosto veloce ...

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('') == ''

I miei test suggeriscono che questo approccio è più veloce delle funzioni che iterano sulla stringa e restituiscono un risultato usando str.join.

0
ChrisP