J'ai actuellement le code suivant
def removeControlCharacters(line):
i = 0
for c in line:
if (c < chr(32)):
line = line[:i - 1] + line[i+1:]
i += 1
return line
Cela ne fonctionne tout simplement pas s'il y a plus d'un caractère à supprimer.
Il y a centaines de caractères de contrôle en unicode. Si vous désinfectez des données provenant du Web ou de toute autre source susceptible de contenir des caractères non ASCII, vous aurez besoin du module unicodedata de Python. La fonction unicodedata.category(…)
renvoie le code de catégorie unicode (par exemple, caractère de contrôle, espace, lettre, etc.) de n’importe quel caractère. Pour les caractères de contrôle, la catégorie commence toujours par "C".
Cet extrait supprime tous les caractères de contrôle d'une chaîne.
import unicodedata
def remove_control_characters(s):
return "".join(ch for ch in s if unicodedata.category(ch)[0]!="C")
Exemples de catégories unicode }:
>>> from unicodedata import category
>>> category('\r') # carriage return --> Cc : control character
'Cc'
>>> category('\0') # null character ---> Cc : control character
'Cc'
>>> category('\t') # tab --------------> Cc : control character
'Cc'
>>> category(' ') # space ------------> Zs : separator, space
'Zs'
>>> category(u'\u200A') # hair space -------> Zs : separator, space
'Zs'
>>> category(u'\u200b') # zero width space -> Cf : control character, formatting
'Cf'
>>> category('A') # letter "A" -------> Lu : letter, uppercase
'Lu'
>>> category(u'\u4e21') # 両 ---------------> Lo : letter, other
'Lo'
>>> category(',') # comma -----------> Po : punctuation
'Po'
>>>
Vous pouvez utiliser str.translate
avec la carte appropriée, par exemple comme ceci:
>>> mpa = dict.fromkeys(range(32))
>>> 'abc\02de'.translate(mpa)
'abcde'
Toute personne intéressée par une classe de caractères regex qui correspond à n’importe quel caractère Unicode control character peut utiliser [\x00-\x1f\x7f-\x9f]
.
Vous pouvez le tester comme ceci:
>>> import unicodedata, re, sys
>>> all_chars = [chr(i) for i in range(sys.maxunicode)]
>>> control_chars = ''.join(c for c in all_chars if unicodedata.category(c) == 'Cc')
>>> expanded_class = ''.join(c for c in all_chars if re.match(r'[\x00-\x1f\x7f-\x9f]', c))
>>> control_chars == expanded_class
True
Donc, pour supprimer les caractères de contrôle en utilisant re
, utilisez ce qui suit:
>>> re.sub(r'[\x00-\x1f\x7f-\x9f]', '', 'abc\02de')
'abcde'
Votre implémentation est incorrecte car la valeur de i
est incorrecte. Cependant, ce n’est pas le seul problème: il utilise également de manière répétée des opérations de chaîne lente, ce qui signifie qu’il s’exécute dans O (n2) au lieu de O (n). Essayez ceci à la place:
return ''.join(c for c in line if ord(c) >= 32)
Et pour Python 2, avec la variable translate
intégrée:
import string
all_bytes = string.maketrans('', '') # String of 256 characters with (byte) value 0 to 255
line.translate(all_bytes, all_bytes[:32]) # All bytes < 32 are deleted (the second argument lists the bytes to delete)
filter(string.printable[:-5].__contains__,line)
Vous modifiez la ligne lors de son itération. Quelque chose comme ''.join([x for x in line if ord(x) >= 32])
C’est la méthode la plus simple, la plus complète et la plus robuste que je connaisse. Cela nécessite toutefois une dépendance externe. Je considère que cela vaut la peine pour la plupart des projets.
pip install regex
import regex as re
def remove_control_characters(str):
return re.sub(r'\p{C}', '', 'my-string')
\p{C}
est la propriété de caractère unicode pour les caractères de contrôle. Vous pouvez donc laisser au consortium unicode les noms de millions de caractères unicode disponibles qui doivent être considérés comme des contrôles. Il existe également d’autres propriétés de caractère extrêmement utiles que j’utilise fréquemment, par exemple \p{Z}
pour tout type d’espace.