Domanda

Io vado a correre

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

su Perl per eliminare i caratteri non stampabili.

In Python non ci sono classi regex POSIX e non posso scrivere [:print:] facendo in modo che significhi quello che voglio.Non conosco alcun modo in Python per rilevare se un carattere è stampabile o meno.

Cosa faresti?

MODIFICARE:Deve supportare anche i caratteri Unicode.Il modo string.printable li eliminerà felicemente dall'output.curses.ascii.isprint restituirà false per qualsiasi carattere Unicode.

È stato utile?

Soluzione

Sfortunatamente l'iterazione sulle stringhe è piuttosto lenta in Python.Le espressioni regolari sono più veloci di un ordine di grandezza per questo genere di cose.Devi solo costruire tu stesso la classe del personaggio.IL unicodedata il modulo è molto utile per questo, specialmente il unicodedata.categoria() funzione.Vedere Database di 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)

Altri suggerimenti

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

import string

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

Potresti provare a impostare un filtro utilizzando il file unicodedata.category() funzione:

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

Vedere la Tabella 4-9 a pagina 175 nella Proprietà dei caratteri del database Unicode per le categorie disponibili

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

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

Questa funzione utilizza la comprensione delle liste e str.join, quindi viene eseguita in tempo lineare anziché O(n^2):

from curses.ascii import isprint

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

Il meglio che ho trovato ora è (grazie ai Python-izer 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?

Quello sotto è più veloce degli altri sopra.Guarda

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

In Python non ci sono classi regex POSIX

Ci sono quando si utilizza il regex biblioteca: https://pypi.org/project/regex/

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

Dalla documentazione:

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

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

(Non sono affiliato, solo un utente.)

Per rimuovere gli "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))

Ancora un'altra opzione in Python 3:

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

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 eseguono l'iterazione sulla stringa e restituiscono un risultato utilizzando str.join.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top