J'ai l'habitude de courir
$s =~ s/[^[:print:]]//g;
sur Perl pour se débarrasser des caractères non imprimables.
En Python, il n'y a pas de classe POSIX regex, et je ne peux pas écrire [: print:] parce que ça veut dire ce que je veux. Je ne connais aucun moyen en Python de détecter si un caractère est imprimable ou non.
Qu'est-ce que tu ferais?
EDIT: Il doit également supporter les caractères Unicode. La méthode string.printable les supprimera volontiers de la sortie. curses.ascii.isprint retournera false pour tout caractère unicode.
Itérer sur des chaînes est malheureusement assez lent en Python. Les expressions régulières sont plus rapides d'un ordre de grandeur pour ce genre de chose. Vous devez juste construire la classe de personnage vous-même. Le module unicodedata est très utile pour cela, en particulier la fonction unicodedata.category (). Voir Base de données de caractères Unicode pour une description des catégories.
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)
Pour autant que je sache, la méthode la plus efficace/pythonique serait:
import string
filtered_string = filter(lambda x: x in string.printable, myStr)
En 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})
Voir cet article de StackOverflow sur la suppression de la ponctuation pour savoir comment .translate () se compare à regex & .replace ()
Vous pouvez essayer de configurer un filtre en utilisant la fonction unicodedata.category()
:
printable = Set('Lu', 'Ll', ...)
def filter_non_printable(str):
return ''.join(c for c in str if unicodedata.category(c) in printable)
Voir les propriétés de caractère de la base de données Unicode pour les catégories disponibles.
Cette fonction utilise la compréhension de liste et str.join, elle tourne donc en temps linéaire au lieu de O (n ^ 2)
from curses.ascii import isprint
def printable(input):
return ''.join(char for char in input if isprint(char))
Le meilleur que j'ai trouvé maintenant est (grâce aux python-izers ci-dessus)
def filter_non_printable(str):
return ''.join([c for c in str if ord(c) > 31 or ord(c) == 9])
C'est la seule façon dont j'ai découvert qui fonctionne avec les caractères/chaînes Unicode
De meilleures options?
En Python, il n'y a pas de classes POSIX regex
Si vous utilisez la bibliothèque regex
: https://pypi.org/project/regex/
Il est bien entretenu et supporte les expressions régulières Unicode, Posix et bien d’autres. L'utilisation (signatures de méthode) est très similaire à la variable re
de Python.
De la documentation:
[[:alpha:]]; [[:^alpha:]]
Les classes de caractères POSIX sont supportées. Celles-ci sont normalement traités comme une forme alternative de
\p{...}
.
(Je ne suis pas affilié, juste un utilisateur.)
Celui ci-dessous fonctionne plus vite que les autres ci-dessus. Regarde
''.join([x if x in string.printable else '' for x in Str])
Pour supprimer les «espaces»,
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))
Encore une autre option dans python 3:
re.sub(f'[^{re.escape(string.printable)}]', '', my_string)
Ce qui suit fonctionnera avec l’entrée Unicode et est assez rapide ...
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('') == ''
Mes propres tests suggèrent que cette approche est plus rapide que les fonctions qui parcourent la chaîne et renvoient un résultat en utilisant str.join
.