Python: Supprimer \ xa0 de la chaîne?

241

J'utilise actuellement Beautiful Soup pour analyser un fichier HTML et appeler get_text(), mais il me semble qu'il me reste beaucoup de \ xa0 Unicode représentant des espaces. Existe-t-il un moyen efficace de les supprimer tous en Python 2.7 et de les transformer en espaces? Je suppose que la question la plus générale serait: existe-t-il un moyen de supprimer le formatage Unicode?

J'ai essayé d'utiliser line = line.replace(u'\xa0',' '):, comme suggéré par un autre thread, mais cela a changé les \ xa0 en u, donc maintenant j'ai des "u" partout à la place. ):

EDIT: Le problème semble être résolu par str.replace(u'\xa0', ' ').encode('utf-8'), mais le simple fait de s'en .encode('utf-8')passer replace()semble le faire cracher des caractères encore plus étranges, \ xc2 par exemple. Quelqu'un peut-il expliquer cela?

zhuyxn
la source
déjà essayé, le codec 'ascii' ne peut pas décoder l'octet 0xa0 en position 0: l'ordinal n'est pas dans la plage (128)
zhuyxn
15
embrasser Unicode. Utilisez u''s au lieu de ''s. :-)
jpaugh
1
a essayé d'utiliser str.replace (u '\ xa0', '') mais a obtenu des "u" partout au lieu de \ xa0s: /
zhuyxn
Si la chaîne est unicode, vous devez utiliser le u' 'remplacement, pas le ' '. La chaîne d'origine est-elle unicode?
pepr

Réponses:

267

\ xa0 est en fait un espace insécable en Latin1 (ISO 8859-1), également chr (160). Vous devez le remplacer par un espace.

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

Lorsque .encode ('utf-8'), il encodera l'unicode en utf-8, cela signifie que chaque unicode pourrait être représenté par 1 à 4 octets. Dans ce cas, \ xa0 est représenté par 2 octets \ xc2 \ xa0.

Lisez sur http://docs.python.org/howto/unicode.html .

Remarque: cette réponse datant de 2012, Python a évolué, vous devriez pouvoir l'utiliser unicodedata.normalizemaintenant

samwize
la source
11
Je ne connais pas grand-chose sur les encodages Unicode et caractères .. mais il semble que unicodedata.normalize serait plus approprié que str.replace
dbr
Le vôtre est un conseil pratique pour les chaînes, mais notez que toutes les références à cette chaîne devront également être remplacées. Par exemple, si vous avez un programme qui ouvre des fichiers et que l'un des fichiers a un espace insécable dans son nom, vous devrez renommer ce fichier en plus d'effectuer ce remplacement.
g33kz0r
1
U + 00a0 est un caractère Unicode insécable qui peut être codé en b'\xa0'octets dans le codage latin1, en deux octets b'\xc2\xa0'dans le codage utf-8. Il peut être représenté comme  en html.
jfs
3
Quand j'essaye, je comprends UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 397: ordinal not in range(128).
gwg
A été coincé pendant 1 heure et a finalement été résolu. Merci beaucoup.
Sadman Hasan
217

Il y a beaucoup de choses utiles dans la unicodedatabibliothèque de Python . L'un d'eux est la .normalize()fonction.

Essayer:

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

Remplacer NFKD par l'une des autres méthodes répertoriées dans le lien ci-dessus si vous n'obtenez pas les résultats que vous recherchez.

Jamie
la source
9
c'est génial. Ce devrait être la réponse acceptée.
Houman
2
Entièrement d'accord. Solution simple, claire, courte et précise. Pouces vers le haut.
Billy Jhon
2
Pas si sûr, vous voudrez peut- normalize('NFKD', '1º\xa0dia')être retourner '1º dia' mais cela retourne '1o dia'
Faccion
1
ah, si le texte est «coréen», n'essayez pas ceci. 글자 가 전부 깨져 버리 네요.
Cho
18

Essayez d'utiliser .strip () à la fin de votre ligne line.strip()a bien fonctionné pour moi

user3590113
la source
15

Après avoir essayé plusieurs méthodes, pour le résumer, voici comment je l'ai fait. Voici deux façons d'éviter / supprimer les caractères \ xa0 de la chaîne HTML analysée.

Supposons que nous ayons notre html brut comme suit:

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

Essayons donc de nettoyer cette chaîne 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'

Le code ci-dessus produit ces caractères \ xa0 dans la chaîne. Pour les supprimer correctement, nous pouvons utiliser deux méthodes.

Méthode n ° 1 (recommandée): la première est la méthode get_text de BeautifulSoup avec l' argument strip comme True. Notre code devient donc:

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éthode n ° 2: L'autre option consiste à utiliser la bibliothèque unicodedata 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'

J'ai également détaillé ces méthodes sur ce blog que vous voudrez peut-être consulter.

Ali Raza Bhayani
la source
Merci, la méthode 1 est ce que je cherchais après tout.
Vasim
12

essaye ça:

string.replace('\\xa0', ' ')
user278064
la source
5
@RyanMartin: cela remplace quatre octets : len(b'\\xa0') == 4mais len(b'\xa0') == 1. Si possible; vous devez corriger en amont qui génère ces échappements.
jfs
12

J'ai rencontré ce même problème lors de l'extraction de certaines données d'une base de données sqlite3 avec python. Les réponses ci-dessus n'ont pas fonctionné pour moi (je ne sais pas pourquoi), mais cela a fonctionné:line = line.decode('ascii', 'ignore') Cependant, mon objectif était de supprimer les \ xa0s, plutôt que de les remplacer par des espaces.

Je l'ai obtenu grâce à ce tutoriel Unicode super utile de Ned Batchelder.

Communauté
la source
14
Vous supprimez maintenant tout ce qui n'est pas un caractère ASCII, vous masquez probablement votre problème réel. Utiliser, 'ignore'c'est comme pousser à travers le levier de vitesse même si vous ne comprenez pas comment fonctionne l'embrayage.
Martijn Pieters
@MartijnPieters Le tutoriel Unicode lié est bon, mais vous avez tout à fait raison - str.encode(..., 'ignore')est l'équivalent de la gestion Unicode de try: ... except: .... Bien qu'il puisse masquer le message d'erreur, il résout rarement le problème.
dbr
1
à des fins telles que le traitement des courriels ou des URL, il semble parfait à utiliser.decode('ascii', 'ignore')
andilabs
1
La réponse de Samwize n'a pas fonctionné pour vous car elle fonctionne sur les chaînes Unicode . line.decode()dans votre réponse suggère que votre entrée est un bytestring (vous ne devez pas faire appel .decode()à une chaîne Unicode (pour l'appliquer, la méthode est supprimée en Python 3). Je ne comprends pas comment il est possible de voir le tutoriel que vous avez lié dans votre réponse et manquez la différence entre les octets et Unicode (ne les mélangez pas)
jfs
8

Je me retrouve ici en recherchant le problème avec le caractère non imprimable. J'utilise MySQL UTF-8 general_ciet m'occupe du langage polonais. Pour les chaînes problématiques, je dois procéder comme suit:

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

C'est juste une solution de contournement rapide et vous devriez probablement essayer quelque chose avec la bonne configuration d'encodage.

andilabs
la source
1
cela fonctionne si textest un bytestring qui représente un texte encodé en utilisant utf-8. Si vous travaillez avec du texte; le décoder en Unicode first ( .decode('utf-8')) et le coder en un bytestring uniquement à la fin (si l'API ne prend pas directement en charge Unicode, par exemple, socket). Toutes les opérations intermédiaires sur le texte doivent être effectuées sur Unicode.
jfs
8

Essayez ce code

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

0xA0 (Unicode) est 0xC2A0 en UTF-8. .encode('utf8')prendra simplement votre Unicode 0xA0 et le remplacera par 0xC2A0 de l'UTF-8. D'où l'apparition de 0xC2s ... L'encodage ne remplace pas, comme vous l'avez probablement réalisé maintenant.

dda
la source
1
0xc2a0est ambigu (ordre des octets). Utilisez b'\xc2\xa0'plutôt des octets littéraux.
jfs
3

C'est l'équivalent d'un caractère d'espace, alors dépouillez-le

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

Dans Beautiful Soup, vous pouvez passer get_text()le paramètre strip, qui supprime les espaces blancs du début et de la fin du texte. Cela supprimera \xa0ou tout autre espace blanc s'il se produit au début ou à la fin de la chaîne. Beautiful Soup a remplacé une chaîne vide par \xa0et cela a résolu le problème pour moi.

mytext = soup.get_text(strip=True)
marque
la source
5
strip=Truene fonctionne que si se &nbsp;trouve au début ou à la fin de chaque bit de texte. Il ne supprimera pas l'espace s'il se trouve entre d'autres caractères du texte.
jfs
1

Version générique avec l'expression régulière (elle supprimera tous les caractères de contrôle):

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

Python le reconnaît comme un caractère d'espace, vous pouvez splitdonc le faire sans arguments et le joindre par un espace blanc normal:

line = ' '.join(line.split())
Jonhy Beebop
la source