Python: ¿Eliminar \ xa0 de la cadena?

241

Actualmente estoy usando Beautiful Soup para analizar un archivo HTML y llamar get_text(), pero parece que me quedan muchos \ xa0 Unicode que representan espacios. ¿Hay alguna manera eficiente de eliminarlos en Python 2.7 y cambiarlos a espacios? Supongo que la pregunta más general sería: ¿hay alguna forma de eliminar el formato Unicode?

Intenté usar:, line = line.replace(u'\xa0',' ')como lo sugirió otro hilo, pero eso cambió los \ xa0's a u's, así que ahora tengo "u" s en todas partes. ):

EDITAR: Parece que el problema se resuelve str.replace(u'\xa0', ' ').encode('utf-8'), pero el hecho de .encode('utf-8')no hacerlo replace()hace que escupe caracteres aún más extraños, \ xc2 por ejemplo. ¿Alguien puede explicar esto?

zhuyxn
fuente
ya lo intenté, el códec 'ascii' no puede decodificar el byte 0xa0 en la posición 0: el ordinal no está en el rango (128)
zhuyxn
15
abrazar a Unicode. Use u''s en lugar de ''s. :-)
jpaugh
1
intenté usar str.replace (u '\ xa0', '') pero obtuve "u" s en todas partes en lugar de \ xa0s: /
zhuyxn
Si la cadena es la unicode, debe usar el u' 'reemplazo, no el ' '. ¿Es la cadena original la unicode?
pepr

Respuestas:

267

\ xa0 es en realidad un espacio sin interrupciones en Latin1 (ISO 8859-1), también chr (160). Deberías reemplazarlo con un espacio.

string = string.replace(u'\xa0', u' ')

Cuando .encode ('utf-8') codificará el unicode a utf-8, eso significa que cada unicode podría estar representado por 1 a 4 bytes. Para este caso, \ xa0 está representado por 2 bytes \ xc2 \ xa0.

Lea sobre http://docs.python.org/howto/unicode.html .

Tenga en cuenta: esta respuesta de 2012, Python ha avanzado, debería poder usarla unicodedata.normalizeahora

samwize
fuente
11
No sé mucho sobre Unicode y las codificaciones de caracteres ... pero parece que unicodedata.normalize sería más apropiado que str.replace
dbr
El suyo es un consejo viable para las cadenas, pero tenga en cuenta que todas las referencias a esta cadena también deberán reemplazarse. Por ejemplo, si tiene un programa que abre archivos y uno de los archivos tiene un espacio continuo en su nombre, deberá cambiar el nombre de ese archivo además de hacer este reemplazo.
g33kz0r
1
U + 00a0 es un carácter Unicode de espacio no rompible que puede codificarse como b'\xa0'byte en la codificación latin1, como dos bytes b'\xc2\xa0'en la codificación utf-8. Se puede representar como  en html.
jfs
3
Cuando intento esto, me sale UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 397: ordinal not in range(128).
gwg
Estaba atrapado durante 1 hora y finalmente resuelto. Muchas gracias.
Sadman Hasan
217

Hay muchas cosas útiles en la unicodedatabiblioteca de Python . Uno de ellos es la .normalize()función.

Tratar:

new_str = unicodedata.normalize("NFKD", unicode_str)

Reemplazar NFKD con cualquiera de los otros métodos enumerados en el enlace anterior si no obtiene los resultados que busca.

Jamie
fuente
99
esto es brillante. Esta debería ser la respuesta aceptada.
Houman
2
Totalmente de acuerdo. Solución fácil, clara, corta y precisa. Pulgares hacia arriba.
Billy Jhon el
2
No estoy tan seguro, es posible que desee normalize('NFKD', '1º\xa0dia')devolver '1º dia' pero devuelve '1o dia'
Facción
1
ah, si el texto es 'COREANO', no intentes esto. 글자 가 전부 깨져 버리 네요.
Cho
18

Intente usar .strip () al final de su línea line.strip()funcionó bien para mí

usuario3590113
fuente
15

Después de probar varios métodos, para resumirlo, así es como lo hice. Las siguientes son dos formas de evitar / eliminar caracteres \ xa0 de una cadena HTML analizada.

Supongamos que tenemos nuestro html en bruto de la siguiente manera:

raw_html = '<p>Dear Parent, </p><p><span style="font-size: 1rem;">This is a test message, </span><span style="font-size: 1rem;">kindly ignore it. </span></p><p><span style="font-size: 1rem;">Thanks</span></p>'

Entonces intentemos limpiar esta cadena HTML:

from bs4 import BeautifulSoup
raw_html = '<p>Dear Parent, </p><p><span style="font-size: 1rem;">This is a test message, </span><span style="font-size: 1rem;">kindly ignore it. </span></p><p><span style="font-size: 1rem;">Thanks</span></p>'
text_string = BeautifulSoup(raw_html, "lxml").text
print text_string
#u'Dear Parent,\xa0This is a test message,\xa0kindly ignore it.\xa0Thanks'

El código anterior produce estos caracteres \ xa0 en la cadena. Para eliminarlos adecuadamente, podemos usar dos formas.

Método n. ° 1 (recomendado): el primero es el método get_text de BeautifulSoup con el argumento strip como True. Por lo tanto, nuestro código se convierte en:

clean_text = BeautifulSoup(raw_html, "lxml").get_text(strip=True)
print clean_text
# Dear Parent,This is a test message,kindly ignore it.Thanks

Método # 2: La otra opción es usar unicodedatos de la biblioteca de Python

import unicodedata
text_string = BeautifulSoup(raw_html, "lxml").text
clean_text = unicodedata.normalize("NFKD",text_string)
print clean_text
# u'Dear Parent,This is a test message,kindly ignore it.Thanks'

También he detallado estos métodos en este blog que quizás desee consultar.

Ali Raza Bhayani
fuente
Gracias, el Método 1 es lo que estaba buscando todo.
Vasim
12

prueba esto:

string.replace('\\xa0', ' ')
usuario278064
fuente
55
@RyanMartin: esto reemplaza cuatro bytes : len(b'\\xa0') == 4pero len(b'\xa0') == 1. Si es posible; deberías arreglar el flujo ascendente que genera estos escapes.
jfs
12

Me encontré con este mismo problema al extraer algunos datos de una base de datos sqlite3 con python. Las respuestas anteriores no funcionaron para mí (no estoy seguro de por qué), pero sí: line = line.decode('ascii', 'ignore')Sin embargo, mi objetivo era eliminar los \ xa0s, en lugar de reemplazarlos con espacios.

Obtuve esto de este tutorial unicode súper útil de Ned Batchelder.

Comunidad
fuente
14
Ahora está eliminando cualquier cosa que no sea un carácter ASCII, probablemente esté enmascarando su problema real. Usar 'ignore'es como empujar la palanca de cambios aunque no entiendas cómo funciona el embrague ...
Martijn Pieters
@MartijnPieters El tutorial unicode vinculado es bueno, pero tiene toda la razón: str.encode(..., 'ignore')es el equivalente de manejo Unicode de try: ... except: .... Si bien puede ocultar el mensaje de error, rara vez resuelve el problema.
dbr
1
para algunos fines, como tratar con EMAIL o URLS, parece perfecto de usar.decode('ascii', 'ignore')
andilabs
1
la respuesta de samwize no funcionó para usted porque funciona en cadenas Unicode . line.decode()en su respuesta sugiere que su entrada es una cadena de bytes (no debe llamar .decode()a una cadena Unicode (para aplicarla, el método se elimina en Python 3). No entiendo cómo es posible ver el tutorial que ha vinculado en su respuesta y se pierda la diferencia entre bytes y Unicode (no mezclarlos).
JFS
8

Termino aquí mientras busco en Google el problema con el carácter no imprimible. Yo uso MySQL UTF-8 general_ciy trato con el lenguaje polaco. Para cadenas problemáticas, debo proceder de la siguiente manera:

text=text.replace('\xc2\xa0', ' ')

Es solo una solución rápida y probablemente debería intentar algo con la configuración de codificación correcta.

andilabs
fuente
1
esto funciona si textes una cadena de bytes que representa un texto codificado usando utf-8. Si está trabajando con texto; decodifíquelo en Unicode primero ( .decode('utf-8')) y codifíquelo en una cadena de bytes solo al final (si la API no es compatible con Unicode directamente, por ejemplo socket). Todas las operaciones intermedias en el texto deben realizarse en Unicode.
jfs
8

Prueba este código

import re
re.sub(r'[^\x00-\x7F]+','','paste your string here').decode('utf-8','ignore').strip()
shiva
fuente
4

0xA0 (Unicode) es 0xC2A0 en UTF-8. .encode('utf8')solo tomará su Unicode 0xA0 y lo reemplazará con UTF-8's 0xC2A0. De ahí la aparición de 0xC2s ... La codificación no está reemplazando, como probablemente ya se haya dado cuenta ahora.

dda
fuente
1
0xc2a0es ambiguo (orden de bytes). Utilice b'\xc2\xa0'bytes literales en su lugar.
jfs
3

Es el equivalente de un personaje espacial, así que quítalo

print(string.strip()) # no more xa0
8bitjunkie
fuente
1

En Beautiful Soup, puede pasar get_text()el parámetro strip, que elimina el espacio en blanco desde el principio y el final del texto. Esto eliminará \xa0o cualquier otro espacio en blanco si ocurre al principio o al final de la cadena. Beautiful Soup reemplazó una cadena vacía con \xa0y esto resolvió el problema para mí.

mytext = soup.get_text(strip=True)
marca
fuente
55
strip=Truefunciona solo si &nbsp;está al principio o al final de cada bit de texto. No eliminará el espacio si está entre otros caracteres en el texto.
jfs
1

Versión genérica con la expresión regular (eliminará todos los caracteres de control):

import re
def remove_control_chart(s):
    return re.sub(r'\\x..', '', s)
ranaFire
fuente
-1

Python lo reconoce como un carácter de espacio, por lo que puede splithacerlo sin argumentos y unirse por un espacio en blanco normal:

line = ' '.join(line.split())
Jonhy Beebop
fuente