Python: удаление \ xa0 из строки?


241

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

Я попытался использовать:, line = line.replace(u'\xa0',' ')как предложено в другом потоке, но это изменило \ xa0 на u, так что теперь у меня вместо этого везде "u". ):

РЕДАКТИРОВАТЬ: Кажется, что проблема решена str.replace(u'\xa0', ' ').encode('utf-8'), но просто .encode('utf-8')без, replace()кажется, заставляет его выплевывать даже более странные символы, например, \ xc2. Кто-нибудь может объяснить это?


уже пробовал, кодек 'ascii' не может декодировать байт 0xa0 в позиции 0: порядковый номер не в диапазоне (128)
— zhuyxn

15
принять Unicode. Используйте u''s вместо ''s. :-)
— jpaugh

1
попытался использовать str.replace (u '\ xa0', ''), но получил \ us везде вместо \ xa0s: /
— zhuyxn

Если строка является Unicode, вы должны использовать u' 'замену, а не ' '. Является ли исходная строка юникодом?
— Пепр

Ответы:


267

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

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

Когда .encode ('utf-8'), он будет кодировать юникод в utf-8, это означает, что каждый юникод может быть представлен от 1 до 4 байтов. Для этого случая \ xa0 представлен 2 байтами \ xc2 \ xa0.

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

Пожалуйста, обратите внимание: этот ответ с 2012 года, Python перешел, вы должны быть в состоянии использовать unicodedata.normalizeсейчас


11
Я не знаю много о Unicode и кодировках символов ... но кажется, что unicodedata.normalize будет более подходящим, чем str.replace
— dbr

Ваш полезный совет для строк, но учтите, что все ссылки на эту строку также необходимо заменить. Например, если у вас есть программа, открывающая файлы, и в имени одного из файлов есть неразрывный пробел в имени, вам потребуется переименовать этот файл в дополнение к этой замене.
— 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
ах, если текст «корейский», не пытайтесь это сделать. 네요 가 전부 깨져 버리 네요.
— Чо

18

Попробуйте использовать .strip () в конце вашей строки, line.strip()у меня получилось


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 метод с аргументом strip в виде 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.

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'- это как толкание рукоятки переключения передач, даже если вы не понимаете, как работает сцепление ..
— Мартин Питерс

@MartijnPieters Связанное руководство по Unicode - это хорошо, но вы абсолютно правы - str.encode(..., 'ignore')это эквивалент обработки Unicode try: ... except: .... Хотя это может скрывать сообщение об ошибке, оно редко решает проблему.
— 2013 г.

1
для некоторых целей, например, для работы с EMAIL или URL-адресами, он идеально подходит для использования.decode('ascii', 'ignore')
— andilabs

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 и заменим на UTF-8 0xC2A0. Следовательно, появление 0xC2s ... Кодировка не заменяет, как вы, вероятно, поняли сейчас.


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.