python - open - reemplaza de manera eficiente los malos caracteres
python unicode utf-8 (6)
A menudo trabajo con texto utf-8 que contiene caracteres como:
/ xc2 / x99
/ xc2 / x95
/ xc2 / x85
etc
Estos personajes confunden otras bibliotecas con las que trabajo, por lo que deben ser reemplazados.
¿Cuál es una forma eficiente de hacer esto, en lugar de:
text.replace(''/xc2/x99'', '' '').replace(''/xc2/x85, ''...'')
Creo que hay un problema subyacente aquí, y podría ser una buena idea investigar y quizás resolverlo, en lugar de simplemente tratar de ocultar los síntomas.
/xc2/x95
es la codificación UTF-8 del carácter U + 0095, que es un carácter de control C1 (MENSAJE EN ESPERA). No es sorprendente que su biblioteca no pueda manejarlo. Pero la pregunta es, ¿cómo entró en sus datos?
Bueno, una posibilidad muy probable es que comenzó como el carácter 0x95 (BULLET) en la codificación de Windows-1252 , se decodificó erróneamente como U + 0095 en lugar del U + 2022 correcto, y luego se codificó en UTF-8. (El término japonés mojibake describe este tipo de error).
Si esto es correcto, puede recuperar los caracteres originales volviendo a ponerlos en Windows-1252 y decodificándolos en Unicode correctamente esta vez. (En estos ejemplos estoy usando Python 3.3, estas operaciones son un poco diferentes en Python 2.)
>>> b''/x95''.decode(''windows-1252'')
''/u2022''
>>> import unicodedata
>>> unicodedata.name(_)
''BULLET''
Si desea hacer esta corrección para todos los caracteres en el rango 0x80-0x99 que son caracteres válidos de Windows-1252, puede usar este enfoque:
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)
Por ejemplo:
>>> restore_windows_1252_characters(''/x95/x99/x85'')
''•™…''
Esto no es "Caracteres Unicode": se siente más como una cadena codificada en UTF-8. (Aunque su prefijo debe ser / xC3, no / xC2 para la mayoría de los caracteres). No debería arrojarlos en el 95% de los casos, a menos que se comunique con un back-end de COBOL. El mundo no está limitado a 26 personajes, ¿sabes?
Hay una lectura concisa para explicar las diferencias entre las cadenas Unicode (lo que se utiliza como un objeto Unicode en python 2 y como cadenas en Python 3 aquí: http://www.joelonsoftware.com/articles/Unicode.html - por favor, para Por el bien de usted, lea eso. Incluso si nunca planea tener algo que no sea inglés en todas sus aplicaciones, aún tropezará con símbolos como € o º que no encajarán en ASCII de 7 bits. Ese artículo lo ayudará a usted. .
Dicho esto, tal vez las bibliotecas que estás utilizando aceptan objetos de python Unicode, y puedes transformar tus cadenas de UTF-8 Python 2 en unicede haciendo:
var_unicode = var.decode("utf-8")
Si realmente necesita ASCII 100% puro, reemplazando todos los caracteres no ASCII, después de decodificar la cadena para unicode, vuelva a codificarlo en ASCII, diciéndole que ignore los caracteres que no encajan en el juego de caracteres con:
var_ascii = var_unicode.encode("ascii", "replace")
Estos caracteres no están en la Biblioteca ASCII
y esa es la razón por la que está recibiendo los errores. Para evitar estos errores, puede hacer lo siguiente mientras lee el archivo.
import codecs
f = codecs.open(''file.txt'', ''r'',encoding=''utf-8'')
Para saber más sobre este tipo de errores, vaya a este enlace .
Si desea eliminar todos los caracteres que no sean ASCII de una cadena, puede usar
text.encode("ascii", "ignore")
Siempre hay expresiones regulares; simplemente enumere todos los caracteres ofensivos dentro de los corchetes así:
import re
print re.sub(r''[/xc2/x99]''," ","Hello/xc2There/x99")
Esto imprime: ''Hola'', con los caracteres no deseados reemplazados por espacios.
Alternativamente, si tiene un personaje de reemplazo diferente para cada uno:
# 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)
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'')