Python: Видалення \ xa0 із рядка?


241

Наразі я використовую Beautiful Soup для розбору HTML-файлів та дзвінків get_text(), але, схоже, мені залишається багато \ xa0 Unicode, що представляє пробіли. Чи є ефективний спосіб видалити їх у Python 2.7 та змінити їх у пробіли? Я думаю, що більш узагальненим буде питання, чи є спосіб видалити форматування Unicode?

Я спробував використовувати: line = line.replace(u'\xa0',' ')як запропонував інший потік, але це змінило \ xa0's на u, тож тепер я маю "u" скрізь. ):

EDIT: Здається, цю проблему вирішує str.replace(u'\xa0', ' ').encode('utf-8'), але, мабуть, .encode('utf-8')без проблем replace()це може виплеснути навіть більш дивні символи, наприклад, xx2. Хтось може це пояснити?


спробував це, кодек "ascii" не може розшифрувати байт 0xa0 у позиції 0: порядковий не в діапазоні (128)
zhuyxn

15
обійняти Unicode. Використовуйте u''s замість ''s. :-)
jpaugh

1
спробував використовувати str.replace (u '\ xa0', ''), але отримав "u" скрізь замість \ xa0s: /
zhuyxn

Якщо рядок є однокодовим, ви повинні використовувати u' 'заміну, а не ' '. Чи є оригінальна рядок unicode?
pepr

Відповіді:


267

\ xa0 - це фактично нерозривний простір у латинській1 (ISO 8859-1), також chr (160). Вам слід замінити пробіл.

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

Коли .encode ('utf-8'), він буде кодувати unicode to utf-8, це означає, що кожен unicode може бути представлений 1 - 4 байтами. У цьому випадку \ xa0 представлений двома байтами \ xc2 \ xa0.

Читайте на http://docs.python.org/howto/unicode.html .

Зверніть увагу: цю відповідь, починаючи з 2012 року, Python перейшов, ви можете використовувати її вже unicodedata.normalizeзараз


11
Я не знаю величезної кількості про кодування Unicode та символів .. але здається, що unicodedata.normalize було б більш доречним, ніж str.replace
декабрь

Ваш - це корисна порада для рядків, але зауважте, що всі посилання на цей рядок також потрібно буде замінити. Наприклад, якщо у вас є програма, яка відкриває файли, а один із файлів має назву без розриву, вам потрібно буде перейменувати цей файл на додаток до цієї заміни.
g33kz0r

1
U + 00a0 - символ нерозривного простору Unicode, який може бути закодований як b'\xa0'байт у кодуванні latin1, як два байти b'\xc2\xa0'в кодуванні utf-8. Його можна представити як  у html.
jfs

3
Коли я спробую це, я отримую UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 397: ordinal not in range(128).
gwg

Був застряг протягом 1 години і нарешті вирішився. Дуже дякую.
Садман Хасан

217

У unicodedataбібліотеці Python є багато корисного . Однією з них є .normalize()функція.

Спробуйте:

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

Заміна NFKD будь-яким з інших способів, перелічених у посиланні вище, якщо ви не отримаєте результатів, за якими ви хочете.


9
це геніально. Це має бути прийнятою відповіддю.
Хоуман

2
Повністю згоден. Легке, чітке, коротке та точне рішення. Пальці вгору.
Біллі Йон

2
Не дуже впевнений, ви можете normalize('NFKD', '1º\xa0dia')повернути "1º dia", але він поверне "1o dia"
Faccion


1
ах, якщо текст "KOREAN", не намагайтеся цього робити. 글자 가 전부 깨져 버리 네요.
Чо


15

Спробувавши кілька методів, підсумовуючи це, я це зробив. Нижче наведено два способи уникнення / видалення символів \ xa0 з проаналізованого рядка HTML.

Припустимо, у нас є сирий html наступним чином:

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

Тому давайте спробуємо очистити цей рядок 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'

Вищевказаний код створює ці символи \ xa0 у рядку. Щоб правильно їх видалити, ми можемо скористатися двома способами.

Спосіб №1 (рекомендується): Перший - метод get_text BeautifulSoup з аргументом смужки як True, то наш код стає:

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

Спосіб №2 . Інший варіант - використовувати бібліотеку python unicodedata

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'

Я також детально описав ці методи в цьому блозі, на який ви можете посилатися.


Дякую, Метод 1 - це те, на що я все шукав.
Васим

12

спробуйте це:

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

5
@RyanMartin: це замінює чотири байти : len(b'\\xa0') == 4але len(b'\xa0') == 1. Якщо можливо; вам слід виправити вгору, що генерує ці втечі.
jfs

12

Я зіткнувся з цією ж проблемою, витягуючи деякі дані з бази даних sqlite3 з python. Наведені вище відповіді не працювали для мене (не знаю чому), але це було так: line = line.decode('ascii', 'ignore')Однак моя мета - видалити \ xa0s, а не замінити їх пробілами.

Я отримав це з цього супер-корисного підручника з унікодом Неда Батчелдера.


14
Тепер ви видаляєте все, що не є символом ASCII, ви, мабуть, маскуєте фактичну проблему. Використовувати 'ignore'це як би проштовхуватися через ручку, навіть якщо ви не розумієте, як працює зчеплення ..
Martijn Pieters

@MartijnPieters Підручник з Unicode добре, але ви абсолютно правильні - str.encode(..., 'ignore')це еквівалент обробки Unicode try: ... except: .... Хоча воно може приховувати повідомлення про помилку, воно рідко вирішує проблему.
1313

1
для таких цілей, як робота з EMAIL або URL- .decode('ascii', 'ignore')
адресами,

1
Відповідь samwize не працювала для вас, оскільки вона працює на рядках Unicode . line.decode()у вашій відповіді підказує, що ваш вхід - це тестування (ви не повинні викликати .decode()рядок Unicode (щоб його застосувати, метод видалено в Python 3). Я не розумію, як можна переглянути підручник, який ви пов'язані у вашій відповіді та пропустіть різницю між байтами та Unicode (не змішуйте їх).
jfs

8

Я закінчую тут, гуглюючи через проблему з недрукованим символом. Я використовую MySQL UTF-8 general_ciі маю справу з польською мовою. Для проблемних рядків я повинен прийняти наступне:

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

Це просто швидке вирішення, і ви, ймовірно, повинні спробувати щось із правильним налаштуванням кодування.


1
це працює, якщо textце тестовий рядок, який представляє текст, закодований за допомогою utf-8. Якщо ви працюєте з текстом; розшифруйте його до Unicode спершу ( .decode('utf-8')) та кодуйте до тестування лише в самому кінці (якщо API не підтримує Unicode безпосередньо, наприклад, socket). Усі проміжні операції над текстом слід виконувати на Unicode.
jfs

8

Спробуйте цей код

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

4

0xA0 (Unicode) - 0xC2A0 в UTF-8. .encode('utf8')просто візьме ваш Unicode 0xA0 і замінить на 0xC2A0 UTF-8. Звідси поява 0xC2 ... Кодування не замінює, як ви, мабуть, зрозуміли зараз.


1
0xc2a0неоднозначний (порядок байт). Використовуйте b'\xc2\xa0'натомість байти.
jfs

3

Це еквівалент космічного персонажа, тому зніміть його

print(string.strip()) # no more xa0

1

У Beautiful Soup ви можете передати get_text()параметр смужки, який позбавляє пробілу з початку та кінця тексту. Це видалить \xa0або будь-який інший пробіл, якщо він з’явиться на початку або в кінці рядка. Beautiful Soup замінив порожню рядок на, \xa0і це вирішило для мене проблему.

mytext = soup.get_text(strip=True)

5
strip=Trueпрацює лише в тому випадку, якщо &nbsp;знаходиться на початку або в кінці кожного фрагмента тексту. Він не видалить пробіл, якщо він знаходиться між іншими символами тексту.
jfs

1

Загальна версія з регулярним виразом (видалить усі контрольні символи):

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

-1

Python розпізнає його як пробільний символ, тож ви можете splitбез аргументів і приєднатися до звичайного пробілу:

line = ' '.join(line.split())
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.