¿Cómo hacer que el intérprete de Python maneje correctamente los caracteres no ASCII en las operaciones de cadena?

Tengo una cadena que se parece a esto:

6Â 918Â 417Â 712 

La forma clara de recortar esta cadena (como entiendo de Python) es simplemente decir que la cadena está en una variable llamada s , obtenemos:

 s.replace('Â ', '') 

Eso debería hacer el truco. Pero, por supuesto, se queja de que el carácter no ASCII '\xc2' en el archivo blabla.py no está codificado.

Nunca pude entender cómo cambiar entre diferentes codificaciones.

Aquí está el código, realmente es lo mismo que arriba, pero ahora está en contexto. El archivo se guarda como UTF-8 en el bloc de notas y tiene el siguiente encabezado:

 #!/usr/bin/python2.4 # -*- coding: utf-8 -*- 

El código:

 f = urllib.urlopen(url) soup = BeautifulSoup(f) s = soup.find('div', {'id':'main_count'}) #making a print 's' here goes well. it shows 6Â 918Â 417Â 712 s.replace('Â ','') save_main_count(s) 

No hay más que en su s.replace

Python 2 usa ascii como la encoding predeterminada para los archivos de origen, lo que significa que debe especificar otra encoding en la parte superior del archivo para usar caracteres unicode que no sean ascii en literales. Python 3 usa utf-8 como la encoding predeterminada para los archivos de origen, por lo que este es un problema menor.

Consulte: http://docs.python.org/tutorial/interpreter.html#source-code-encoding

Para habilitar la encoding de fuente utf-8, esto iría en una de las dos líneas superiores:

 # -*- coding: utf-8 -*- 

Lo anterior está en los documentos, pero esto también funciona:

 # coding: utf-8 

Consideraciones adicionales:

  • El archivo fuente también debe guardarse utilizando la encoding correcta en su editor de texto.

  • En Python 2, el literal Unicode debe tener una u antes, como en s.replace(u"Â ", u"") Pero en Python 3, solo use comillas. En Python 2, puede from __future__ import unicode_literals para obtener el comportamiento de Python 3, pero tenga en cuenta que esto afecta a todo el módulo actual.

  • s.replace(u"Â ", u"") también fallará si s no es una cadena Unicode.

  • string.replace devuelve una nueva cadena y no se edita en su lugar, así que asegúrate de estar usando el valor de retorno también

 def removeNonAscii(s): return "".join(filter(lambda x: ord(x)<128, s)) 

edición: mi primer impulso es usar un filtro, pero la expresión del generador es más eficiente en memoria (y más corta) ...

 def removeNonAscii(s): return "".join(i for i in s if ord(i)<128) 

Tenga en cuenta que está garantizado que esto funcione con la encoding UTF-8 (porque todos los bytes en caracteres de múltiples bytes tienen el bit más alto establecido en 1).

 >>> unicode_string = u"hello aåbäcö" >>> unicode_string.encode("ascii", "ignore") 'hello abc' 

El siguiente código reemplazará todos los caracteres no ASCII con signos de interrogación.

 "".join([x if ord(x) < 128 else '?' for x in s]) 

Utilizando Regex:

 import re strip_unicode = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)") print strip_unicode.sub('', u'6Â 918Â 417Â 712') 

Demasiado tarde para una respuesta, pero la cadena original estaba en UTF-8 y ‘\ xc2 \ xa0’ es UTF-8 para NO-BREAK SPACE. Simplemente decodifique la cadena original como s.decode('utf-8') (\ xa0 se muestra como un espacio cuando se decodifica incorrectamente como Windows-1252 o latin-1:

Ejemplo (Python 3)

 s = b'6\xc2\xa0918\xc2\xa0417\xc2\xa0712' print(s.decode('latin-1')) # incorrectly decoded u = s.decode('utf8') # correctly decoded print(u) print(u.replace('\N{NO-BREAK SPACE}','_')) print(u.replace('\xa0','-')) # \xa0 is Unicode for NO-BREAK SPACE 

Salida

 6Â 918Â 417Â 712 6 918 417 712 6_918_417_712 6-918-417-712 
 #!/usr/bin/env python # -*- coding: utf-8 -*- s = u"6Â 918Â 417Â 712" s = s.replace(u"Â", "") print s 

Esto imprimirá 6 918 417 712

Sé que es un hilo viejo, pero me sentí obligado a mencionar el método de traducción, que siempre es una buena manera de reemplazar todos los códigos de caracteres por encima de 128 (u otro si es necesario).

Uso : str. traducir ( tabla [, deletechars] )

 >>> trans_table = ''.join( [chr(i) for i in range(128)] + [' '] * 128 ) >>> 'Résultat'.translate(trans_table) 'R sultat' >>> '6Â 918Â 417Â 712'.translate(trans_table) '6 918 417 712' 

A partir de Python 2.6 , también puede configurar la tabla como Ninguno y usar deletechars para eliminar los caracteres que no desea, como en los ejemplos que se muestran en los documentos estándar en http://docs.python.org/library/stdtypes. html .

Con las cadenas Unicode, la tabla de traducción no es una cadena de 256 caracteres, sino un dict con el ord () de caracteres relevantes como claves. Pero de todos modos, obtener una cadena ascii adecuada de una cadena Unicode es bastante simple, usando el método mencionado anteriormente por truppo, a saber: unicode_string.encode (“ascii”, “ignore”)

Como resumen, si, por alguna razón, absolutamente necesita obtener una cadena ascii (por ejemplo, cuando raise Exception, ascii_message una excepción estándar con una excepción de raise Exception, ascii_message ), puede usar la siguiente función:

 trans_table = ''.join( [chr(i) for i in range(128)] + ['?'] * 128 ) def ascii(s): if isinstance(s, unicode): return s.encode('ascii', 'replace') else: return s.translate(trans_table) 

Lo bueno de traducir es que realmente puede convertir caracteres acentuados en caracteres ascii relevantes no acentuados en lugar de simplemente eliminarlos o reemplazarlos por ‘?’. Esto suele ser útil, por ejemplo, para fines de indexación.

 s.replace(u'Â ', '') # u before string is important 

y haz tu archivo .py unicode.

Este es un truco sucio, pero puede funcionar.

 s2 = "" for i in s: if ord(i) < 128: s2 += i 

Por lo que valía, mi conjunto de caracteres era utf-8 y había incluido la clásica línea ” # -*- coding: utf-8 -*- “.

Sin embargo, descubrí que no tenía Universal Newlines al leer estos datos de una página web.

Mi texto tenía dos palabras, separadas por ” \r\n “. Solo estaba dividiendo en el \n reemplazando el "\n" .

Una vez que hice un bucle y vi el conjunto de caracteres en cuestión, me di cuenta del error.

Por lo tanto, también podría estar dentro del conjunto de caracteres ASCII , pero un personaje que no esperaba.