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.