remplacer efficacement les mauvais caractères

je travaille souvent avec des textes utf-8 contenant des caractères comme:

xc2x99

xc2x95

xc2x85

etc

ces caractères confondent d'autres bibliothèques avec lesquelles je travaille et doivent donc être remplacés.

Ce qui est une manière efficace de faire cela, au lieu de:

text.replace('xc2x99', ' ').replace('xc2x85, '...')
23
demandé sur hoju 2011-07-07 15:31:07

6 réponses

il y a toujours des expressions régulières; il suffit d'énumérer tous les caractères offensants entre crochets comme ceci:

import re
print re.sub(r'[\xc2\x99]'," ","Hello\xc2There\x99")

cette gravure: 'Hello There ', avec les caractères non désirés remplacés par des espaces.

alternativement, si vous avez un caractère de remplacement différent pour chacun:

# remove annoying characters
chars = {
    '\xc2\x82' : ',',        # High code comma
    '\xc2\x84' : ',,',       # High code double comma
    '\xc2\x85' : '...',      # Tripple dot
    '\xc2\x88' : '^',        # High carat
    '\xc2\x91' : '\x27',     # Forward single quote
    '\xc2\x92' : '\x27',     # Reverse single quote
    '\xc2\x93' : '\x22',     # Forward double quote
    '\xc2\x94' : '\x22',     # Reverse double quote
    '\xc2\x95' : ' ',
    '\xc2\x96' : '-',        # High hyphen
    '\xc2\x97' : '--',       # Double hyphen
    '\xc2\x99' : ' ',
    '\xc2\xa0' : ' ',
    '\xc2\xa6' : '|',        # Split vertical bar
    '\xc2\xab' : '<<',       # Double less than
    '\xc2\xbb' : '>>',       # Double greater than
    '\xc2\xbc' : '1/4',      # one quarter
    '\xc2\xbd' : '1/2',      # one half
    '\xc2\xbe' : '3/4',      # three quarters
    '\xca\xbf' : '\x27',     # c-single quote
    '\xcc\xa8' : '',         # modifier - under curve
    '\xcc\xb1' : ''          # modifier - under line
}
def replace_chars(match):
    char = match.group(0)
    return chars[char]
return re.sub('(' + '|'.join(chars.keys()) + ')', replace_chars, text)
29
répondu Nate 2011-07-08 13:36:14

je pense qu'il y a un problème sous-jacent ici, et il pourrait être une bonne idée à étudier et peut-être le résoudre, plutôt que d'essayer de couvrir les symptômes.

\xc2\x95 est l'encodage UTF-8 du caractère U+0095, qui est un C1 control character (message WAITING). Il n'est pas surprenant que votre bibliothèque ne peut pas gérer. Mais la question est, comment est-il entré dans vos données?

Eh bien, un très la possibilité probable est qu'il a commencé comme le caractère 0x95 (balle) dans le Windows-1252 encodage, a été incorrectement décodé comme U+0095 au lieu de la bonne U+2022, puis encodé dans UTF-8. (Le terme japonais mojibake décrit ce genre d'erreur.)

Si ceci est correct, alors vous pouvez récupérer les caractères originaux en les mettant de nouveau dans Windows-1252 et ensuite les décoder dans Unicode correctement cette fois. (Dans ces exemples, J'utilise Python 3.3; ces opérations sont un peu différentes en Python 2.)

>>> b'\x95'.decode('windows-1252')
'\u2022'
>>> import unicodedata
>>> unicodedata.name(_)
'BULLET'

si vous voulez faire cette correction pour tous les caractères dans la gamme 0x80–0x99 qui sont valides Windows-1252 caractères, vous pouvez utiliser cette approche:

def restore_windows_1252_characters(s):
    """Replace C1 control characters in the Unicode string s by the
    characters at the corresponding code points in Windows-1252,
    where possible.

    """
    import re
    def to_windows_1252(match):
        try:
            return bytes([ord(match.group(0))]).decode('windows-1252')
        except UnicodeDecodeError:
            # No character at the corresponding code point: remove it.
            return ''
    return re.sub(r'[\u0080-\u0099]', to_windows_1252, s)

par exemple:

>>> restore_windows_1252_characters('\x95\x99\x85')
'•™…'
20
répondu Gareth Rees 2013-09-24 14:50:22

si vous voulez supprimer tous les caractères non-ASCII d'une chaîne, vous pouvez utiliser

text.encode("ascii", "ignore")
11
répondu Tim Pietzcker 2011-07-07 11:47:22
import unicodedata

# Convert to unicode
text_to_uncicode = unicode(text, "utf-8")           

# Convert back to ascii
text_fixed = unicodedata.normalize('NFKD',text_to_unicode).encode('ascii','ignore')         
2
répondu Ady 2017-04-27 07:49:00

ce n'est pas" Unicode caractères " - il se sent plus comme ceci une chaîne encodée UTF-8. (Bien que votre préfixe soit \xC3, pas \xC2 pour la plupart des caractères). Vous ne devrait pas juste les jeter dans 95% des cas, à moins que vous ne communiquiez avec un arrière-plan COBOL. Le monde ne se limite pas à 26 personnages, vous savez.

il y a une lecture concise pour expliquer les différences entre les chaînes Unicode (ce qui est utilisé comme un objet Unicode en python 2 et comme cordes en Python 3 ici: http://www.joelonsoftware.com/articles/Unicode.html - s'il vous plaît, pour votre bien lire cela. Même si vous n'avez jamais l'intention d'avoir quoi que ce soit qui n'est pas anglais dans toutes vos applications, vous tomberez toujours sur des symboles comme € ou º qui ne rentreront pas dans 7 bit ASCII. Cet article va vous aider.

cela dit, peut-être que les bibliothèques que vous utilisez acceptent les objets Unicode python, et vous pouvez transformer votre UTF-8 Python 2 chaînes en unidoce en faisant:

var_unicode = var.decode("utf-8")

si vous avez vraiment besoin de 100% d'ASCII pur, remplaçant tous les caractères non ASCII, après décoder la chaîne de caractères à unicode, ré-encoder à ASCII, lui dire d'ignorer les caractères qui ne correspondent pas dans le jeu de caractères avec:

var_ascii = var_unicode.encode("ascii", "replace")
0
répondu jsbueno 2011-07-07 14:13:42

ces caractères ne sont pas dans la bibliothèque ASCII et c'est la raison pour laquelle vous obtenez les erreurs. Pour éviter ces erreurs, vous pouvez faire ce qui suit en lisant le fichier.

import codecs   
f = codecs.open('file.txt', 'r',encoding='utf-8')

pour en savoir plus sur ce type d'erreurs, allez sur ce lien .

0
répondu Mokshith Sandeep 2016-11-22 08:18:07