Python: Removendo \ xa0 da string?

241

Atualmente, estou usando a Beautiful Soup para analisar um arquivo HTML e chamar get_text(), mas parece que estou ficando com muitos \ xa0 Unicode representando espaços. Existe uma maneira eficiente de remover todos eles no Python 2.7 e transformá-los em espaços? Eu acho que a pergunta mais generalizada seria, existe uma maneira de remover a formatação Unicode?

Eu tentei usar line = line.replace(u'\xa0',' '):, como sugerido por outro thread, mas isso mudou os \ xa0 para u, então agora tenho "u" em todo lugar. ):

EDIT: O problema parece ter sido resolvido str.replace(u'\xa0', ' ').encode('utf-8'), mas apenas ficar .encode('utf-8')sem replace()parece causar caracteres ainda mais estranhos, \ xc2 por exemplo. Alguém pode explicar isso?

zhuyxn
fonte
tentou que já, 'ASCII' codec não pode descodificar bytes 0xa0 na posição 0: não ordinal na gama (128)
zhuyxn
15
abraçar Unicode. Use u''s em vez de ''s. :-)
jpaugh 12/06
1
tentou usar str.replace (u '\ xa0', ' '), mas tem "u" em toda parte, em vez de \ xa0s: /
zhuyxn
Se a string for unicode, você precisará usar a u' 'substituição, não a ' '. A cadeia original é a unicode?
PEPR

Respostas:

267

\ xa0 é realmente um espaço sem quebra no Latin1 (ISO 8859-1), também chr (160). Você deve substituí-lo por um espaço.

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

Quando .encode ('utf-8'), ele codifica o unicode para utf-8, o que significa que cada unicode pode ser representado por 1 a 4 bytes. Nesse caso, \ xa0 é representado por 2 bytes \ xc2 \ xa0.

Leia em http://docs.python.org/howto/unicode.html .

Observação: nesta resposta, a partir de 2012, o Python seguiu em frente, você deve poder usar unicodedata.normalizeagora

samwize
fonte
11
Eu não sei uma quantidade enorme sobre Unicode e codificação de caracteres .. mas parece que unicodedata.normalize seria mais apropriado do que str.replace
DBR
Seu conselho é viável para cadeias, mas observe que todas as referências a essa cadeia também precisarão ser substituídas. Por exemplo, se você possui um programa que abre arquivos e um dos arquivos possui um espaço sem interrupção em seu nome, será necessário renomear esse arquivo, além de fazer essa substituição.
precisa saber é o seguinte
1
U + 00a0 é um caractere Unicode de espaço inquebrável que pode ser codificado como b'\xa0'byte na codificação latin1, como dois bytes b'\xc2\xa0'na codificação utf-8. Pode ser representado como  em html.
precisa
3
Quando eu tento isso, eu entendo UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 397: ordinal not in range(128).
Gwg 28/05
Ficou preso por 1 hora e finalmente resolvido. Muito obrigado.
Sadman Hasan
217

Há muitas coisas úteis na unicodedatabiblioteca do Python . Um deles é a .normalize()função.

Experimentar:

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

Substituindo NFKD por qualquer um dos outros métodos listados no link acima, se você não obtiver os resultados que deseja.

Jamie
fonte
9
isto é brilhante. Essa deve ser a resposta aceita.
Houman 27/02
2
Concordo plenamente. Solução fácil, clara, curta e direta. Afirmativo.
Billy Jhon
2
Não tenho tanta certeza, você pode querer normalize('NFKD', '1º\xa0dia')retornar '1º dia', mas ele retorna '1º dia'
Faccion 8/11/17
3
aqui está a documentação sobreunicodedata.normalize
TT-- 4/17/17
1
ah, se o texto for 'COREANO', não tente isso. 네요 가 전부 깨져 버리 네요.
Cho
18

Tente usar .strip () no final da sua linha line.strip()funcionou bem para mim

user3590113
fonte
15

Depois de tentar vários métodos, para resumir, foi assim que eu fiz. A seguir, estão duas maneiras de evitar / remover caracteres \ xa0 da string HTML analisada.

Suponha que temos nosso html bruto da seguinte forma:

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>'

Então, vamos tentar limpar essa string 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'

O código acima produz esses caracteres \ xa0 na cadeia de caracteres. Para removê-los corretamente, podemos usar duas maneiras.

Método 1 (recomendado): O primeiro é o método get_text da BeautifulSoup com o argumento strip como True. Portanto, nosso código se torna:

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: A outra opção é usar a biblioteca unicodedata do 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'

Também detalhei esses métodos neste blog que você pode consultar.

Ali Raza Bhayani
fonte
Obrigado, o método 1 é o que eu estava procurando.
Vasim 5/02/19
12

tente isto:

string.replace('\\xa0', ' ')
user278064
fonte
5
@RyanMartin: substitui quatro bytes : len(b'\\xa0') == 4mas len(b'\xa0') == 1. Se possível; você deve corrigir o montante que gera essas fugas.
precisa saber é
12

Corri para o mesmo problema, puxando alguns dados de um banco de dados sqlite3 com python. As respostas acima não funcionaram para mim (não sei por quê), mas funcionou: line = line.decode('ascii', 'ignore')No entanto, meu objetivo era excluir os \ xa0s, em vez de substituí-los por espaços.

Eu peguei isso neste tutorial unicode super útil de Ned Batchelder.

Comunidade
fonte
14
Agora você está removendo qualquer coisa que não seja um caractere ASCII, mas provavelmente está ocultando seu problema real. Usar 'ignore'é como empurrar a alavanca de câmbio, mesmo que você não entenda como a embreagem funciona ..
Martijn Pieters
@MartijnPieters O tutorial unicode vinculado é bom, mas você está completamente correto - str.encode(..., 'ignore')é o equivalente a manipulação de Unicode try: ... except: .... Embora possa ocultar a mensagem de erro, raramente resolve o problema.
dbr 9/09/13
1
para alguns fins, como lidar com e-mail ou URLS parece perfeito para uso.decode('ascii', 'ignore')
andilabs
1
A resposta do samwize não funcionou para você porque funciona em strings Unicode . line.decode()na sua resposta sugere que sua entrada é uma bytestring (você não deve chamar .decode()uma string Unicode (para aplicá-la, o método é removido no Python 3.) Eu não entendo como é possível ver o tutorial que você ligado em sua resposta e perder a diferença entre bytes e Unicode (não misturá-los).
jfs
8

Acabo aqui pesquisando o problema com caracteres não imprimíveis. Eu uso o MySQL UTF-8 general_cie lido com a linguagem polonesa. Para cadeias problemáticas, tenho que proceder da seguinte maneira:

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

É apenas uma solução rápida e você provavelmente deve tentar algo com a configuração de codificação correta.

andilabs
fonte
1
isso funciona se textfor uma bytestring que representa um texto codificado usando utf-8. Se você estiver trabalhando com texto; decodifique-o primeiro para Unicode ( .decode('utf-8')) e codifique-o para uma bytestring apenas no final (se a API não suportar diretamente Unicode, por exemplo, socket). Todas as operações intermediárias no texto devem ser executadas em Unicode.
JFS
8

Experimente este código

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

0xA0 (Unicode) é 0xC2A0 em UTF-8. .encode('utf8')basta pegar seu Unicode 0xA0 e substituí-lo pelo 0xC2A0 da UTF-8. Daí a aparição de 0xC2s ... A codificação não está substituindo, como você provavelmente já percebeu agora.

dda
fonte
1
0xc2a0é ambíguo (ordem dos bytes). Use b'\xc2\xa0'bytes literais.
JFS
3

É o equivalente a um caractere de espaço, então tire-o

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

Em Beautiful Soup, você pode passar get_text()o parâmetro strip, que retira o espaço em branco do início e do final do texto. Isso removerá \xa0ou qualquer outro espaço em branco se ocorrer no início ou no final da string. Beautiful Soup substituiu uma string vazia por \xa0e isso resolveu o problema para mim.

mytext = soup.get_text(strip=True)
Marca
fonte
5
strip=Truefunciona apenas se &nbsp;estiver no início ou no final de cada bit de texto. Não removerá o espaço se estiver entre outros caracteres no texto.
JFS
1

Versão genérica com a expressão regular (removerá todos os caracteres de controle):

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

O Python o reconhece como um caractere de espaço, então você pode splitusá-lo sem argumentos e juntar-se por um espaço em branco normal:

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