Expresión regular que encuentra y reemplaza caracteres no-ascii con Python

Necesito cambiar algunos caracteres que no son ASCII a ‘_’. Por ejemplo,

 Tannh ‰ usuario -> Tannh_user
  • Si uso expresiones regulares con Python, ¿cómo puedo hacer esto?
  • ¿Hay una mejor manera de hacer esto sin usar RE?

Actualizado para Python 3:

>>> 'Tannh‰user'.encode().decode('ascii', 'replace').replace(u'\ufffd', '_') 'Tannh___user' 

Primero creamos una cadena de bytes usando encode() – usa el códec UTF-8 de forma predeterminada. Si tiene una cadena de bytes, por supuesto, omita este paso de encoding. Luego lo convertimos en una cadena “normal” usando el códec ascii.

Esto utiliza la propiedad de UTF-8 de que todos los caracteres que no son ASCII están codificados como secuencia de bytes con valor> = 0x80.


Respuesta original – para Python 2:

Cómo hacerlo usando el método str.decode :

 >>> 'Tannh‰user'.decode('ascii', 'replace').replace(u'\ufffd', '_') u'Tannh___user' 

(Obtiene una cadena unicode , así que str a str si la necesita).

También puede convertir unicode a str , por lo que un carácter no ASCII se reemplaza por uno ASCII. Pero el problema es que unicode.encode with replace traduce los caracteres que no son ASCII a '?' , así que no sabes si el signo de interrogación ya estaba allí antes; Ver solución de Ignacio Vázquez-Abrams.


De otra manera, utilizando ord() y comparando el valor de cada carácter si se ajusta en el rango ASCII (0-127), esto funciona para cadenas unicode y para str en utf-8, latin y algunas otras codificaciones:

 >>> s = 'Tannh‰user' # or u'Tannh‰user' in Python 2 >>> >>> ''.join(c if ord(c) < 128 else '_' for c in s) 'Tannh_user' 
 re.sub(r'[^\x00-\x7F]', '_', theString) 

Esto funcionará si theString es unicode, o una cadena en una encoding donde ASCII ocupa los valores 0 a 0x7F (latin-1, UTF-8, etc.).

Usando el soporte de Python para codificaciones de caracteres:

 # coding: utf8 import codecs def underscorereplace_errors(exc): return (u'_', exc.end) codecs.register_error('underscorereplace', underscorereplace_errors) print u'Tannh‰user'.encode('ascii', 'underscorereplace') 

Prefiero llamar ord a cada carácter de la cadena, 1 por 1. Si ord([char]) >= 128 el carácter no es un carácter ascii y debe reemplazarse.

Si sabe qué caracteres desea reemplazar, puede aplicar métodos de cadena.

 mystring.replace('oldchar', 'newchar') 

Contestar la pregunta

 '[\u0080-\uFFFF]' 

coincidirá con cualquier carácter UTF-8 que no esté en el rango de los primeros 128 caracteres

 re.sub('[\u0080-\uFFFF]+', '_', x) 

Reemplazará cualquier secuencia de caracteres consecutivos no escénicos con un guión bajo.