Python: Xóa \ xa0 khỏi chuỗi?


239

Tôi hiện đang sử dụng Beautiful Soup để phân tích một tệp HTML và gọi get_text(), nhưng có vẻ như tôi bị bỏ lại rất nhiều khoảng trống đại diện cho Unicode. Có cách nào hiệu quả để loại bỏ tất cả chúng trong Python 2.7 và thay đổi chúng thành không gian không? Tôi đoán câu hỏi khái quát hơn sẽ là, có cách nào để xóa định dạng Unicode không?

Tôi đã thử sử dụng : line = line.replace(u'\xa0',' '), như được đề xuất bởi một chủ đề khác, nhưng điều đó đã thay đổi \ xa0 thành u, vì vậy bây giờ tôi có "u" ở khắp mọi nơi thay thế. ):

EDIT: Vấn đề dường như được giải quyết bằng str.replace(u'\xa0', ' ').encode('utf-8'), nhưng chỉ làm .encode('utf-8')mà không làm replace()cho nó phát ra ngay cả các ký tự kỳ lạ, ví dụ như \ xc2. Bất cứ ai có thể giải thích điều này?


đã thử rồi, codec 'ascii' không thể giải mã byte 0xa0 ở vị trí 0: thứ tự không nằm trong phạm vi (128)
zhuyxn

15
nắm lấy Unicode. Sử dụng u''s thay vì ''s. :-)
jpaugh

1
đã thử sử dụng str.replace (u '\ xa0', '') nhưng có "u" ở khắp mọi nơi thay vì \ xa0s: /
zhuyxn

Nếu chuỗi là unicode, bạn phải sử dụng u' 'thay thế, không phải ' '. Là chuỗi gốc là unicode?
pepr

Câu trả lời:


265

\ xa0 thực sự là không gian không phá vỡ trong tiếng Latin1 (ISO 8859-1), cũng chr (160). Bạn nên thay thế nó bằng một không gian.

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

Khi .encode ('utf-8'), nó sẽ mã hóa unicode thành utf-8, điều đó có nghĩa là mọi unicode có thể được biểu thị bằng 1 đến 4 byte. Trong trường hợp này, \ xa0 được biểu thị bằng 2 byte \ xc2 \ xa0.

Đọc trên http://docs.python.org/howto/unicode.html .

Xin lưu ý: câu trả lời này từ năm 2012, Python đã chuyển sang, bạn sẽ có thể sử dụng unicodedata.normalizengay bây giờ


11
Tôi không biết một số tiền rất lớn về Unicode và bảng mã ký tự .. nhưng nó có vẻ như unicodedata.normalize sẽ là thích hợp hơn str.replace
DBR

Bạn là lời khuyên khả thi cho các chuỗi, nhưng lưu ý rằng tất cả các tham chiếu đến chuỗi này cũng sẽ cần phải được thay thế. Ví dụ: nếu bạn có một chương trình mở tệp và một trong các tệp có không gian không phá vỡ trong tên của nó, bạn sẽ cần đổi tên tệp đó ngoài việc thực hiện thay thế này.
g33kz0r

1
U + 00a0 là ký tự Unicode không gian không thể phá vỡ , có thể được mã hóa dưới dạng b'\xa0'byte trong mã hóa latin1, dưới dạng hai byte b'\xc2\xa0'trong mã hóa utf-8. Nó có thể được biểu diễn như  trong html.
JFS

3
Khi tôi thử điều này, tôi nhận được UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 397: ordinal not in range(128).
gwg

Đã bị mắc kẹt trong 1 giờ và cuối cùng đã được giải quyết. Cảm ơn rất nhiều.
Sadman Hasan

215

Có nhiều thứ hữu ích trong unicodedatathư viện của Python . Một trong số đó là .normalize()chức năng.

Thử:

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

Thay thế NFKD bằng bất kỳ phương pháp nào khác được liệt kê trong liên kết ở trên nếu bạn không nhận được kết quả mà bạn mong muốn.


9
điều này thật tuyệt vời Đây phải là câu trả lời được chấp nhận.
Houman

2
Hoàn toàn đồng ý. Dễ dàng, rõ ràng, ngắn gọn và giải pháp cho điểm. Đồng ý.
Billy Jhon

2
Không chắc lắm, bạn có thể muốn normalize('NFKD', '1º\xa0dia')trả về '1 º dia' nhưng nó trả về '1o dia'
Faccion


1
à, nếu văn bản là 'HÀN QUỐC', đừng thử điều này. 글자 가 전부.
Cho


14

Sau khi thử một vài phương pháp, để tóm tắt nó, đây là cách tôi đã làm. Sau đây là hai cách để tránh / xóa \ xa0 ký tự khỏi chuỗi HTML được phân tích cú pháp.

Giả sử chúng ta có html thô như sau:

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

Vì vậy, hãy thử làm sạch chuỗi HTML này:

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ạn mã trên tạo ra các ký tự \ xa0 trong chuỗi. Để loại bỏ chúng đúng cách, chúng ta có thể sử dụng hai cách.

Phương thức # 1 (Được khuyến nghị): Cách đầu tiên là phương thức get lòng của BeautifulSoup với đối số dải là True Vì vậy, mã của chúng tôi trở thành:

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

Phương pháp # 2: Tùy chọn khác là sử dụng thư viện của python unicodingata

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'

Tôi cũng đã chi tiết các phương pháp này trên blog này mà bạn có thể muốn tham khảo.


Cảm ơn bạn, Phương pháp 1 là những gì tôi đã tìm kiếm tất cả sau.
Vasim

12

thử cái này:

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

5
@RyanMartin: cái này thay thế bốn byte : len(b'\\xa0') == 4nhưng len(b'\xa0') == 1. Nếu có thể; bạn nên sửa lỗi ngược dòng tạo ra các lối thoát này.
JFS

12

Tôi gặp vấn đề tương tự khi lấy một số dữ liệu từ cơ sở dữ liệu sqlite3 bằng python. Các câu trả lời trên không hiệu quả với tôi (không chắc tại sao), nhưng điều này đã làm:line = line.decode('ascii', 'ignore') Tuy nhiên, mục tiêu của tôi là xóa \ xa0s, thay vì thay thế chúng bằng dấu cách.

Tôi đã nhận được điều này từ hướng dẫn unicode siêu hữu ích này của Ned Batchelder.


14
Bây giờ bạn đang xóa bất cứ thứ gì không phải là ký tự ASCII, có lẽ bạn đang che giấu vấn đề thực sự của mình. Việc sử dụng 'ignore'giống như lách qua cần số mặc dù bạn không hiểu cách thức hoạt động của bộ ly hợp ..
Martijn Pieters

@MartijnPieters Hướng dẫn unicode được liên kết là tốt, nhưng bạn hoàn toàn chính xác - str.encode(..., 'ignore')là tương đương xử lý Unicode try: ... except: .... Mặc dù nó có thể ẩn thông báo lỗi, nhưng nó hiếm khi giải quyết vấn đề.
dbr

1
đối với một số mục đích như giao dịch với EMAIL hoặc URLS, có vẻ như hoàn hảo để sử dụng.decode('ascii', 'ignore')
andilabs

1
Câu trả lời của samwize không phù hợp với bạn vì nó hoạt động trên các chuỗi Unicode . line.decode()trong câu trả lời của bạn cho thấy rằng đầu vào của bạn là một bytestring (bạn không nên gọi .decode()chuỗi Unicode (để thực thi nó, phương thức được loại bỏ trong Python 3). Tôi không hiểu làm thế nào có thể xem hướng dẫn mà bạn đã có thể xem được liên kết trong câu trả lời của bạn và bỏ lỡ sự khác biệt giữa byte và Unicode (không trộn lẫn chúng).
jfs

8

Tôi kết thúc ở đây trong khi googling cho vấn đề với nhân vật không in được. Tôi sử dụng MySQL UTF-8 general_civà đối phó với ngôn ngữ đánh bóng. Đối với các chuỗi có vấn đề, tôi phải mua như sau:

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

Nó chỉ là cách giải quyết nhanh và bạn chắc chắn nên thử một cái gì đó với thiết lập mã hóa đúng.


1
điều này hoạt động nếu textlà một bytestring đại diện cho một văn bản được mã hóa bằng utf-8. Nếu bạn đang làm việc với văn bản; trước tiên hãy giải mã nó thành Unicode ( .decode('utf-8')) và mã hóa nó thành một phần phụ chỉ ở cuối (nếu API không hỗ trợ Unicode trực tiếp, vd socket). Tất cả các hoạt động trung gian trên văn bản nên được thực hiện trên Unicode.
JFS

8

Hãy thử mã này

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

4

0xA0 (Unicode) là 0xC2A0 trong UTF-8. .encode('utf8')sẽ chỉ lấy Unicode 0xA0 của bạn và thay thế bằng 0xC2A0 của UTF-8. Do đó, sự xuất hiện của 0xC2s ... Mã hóa không thay thế, như bạn có thể nhận ra bây giờ.


1
0xc2a0là mơ hồ (thứ tự byte). Sử dụng b'\xc2\xa0'byte theo nghĩa đen thay thế.
JFS

3

Nó tương đương với một nhân vật không gian, vì vậy hãy lột nó ra

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

1

Trong Beautiful Soup, bạn có thể truyền get_text()tham số dải, dải màu trắng từ đầu và cuối văn bản. Điều này sẽ loại bỏ \xa0hoặc bất kỳ khoảng trắng nào khác nếu nó xảy ra ở đầu hoặc cuối chuỗi. Beautiful Soup đã thay thế một chuỗi trống bằng \xa0và điều này đã giải quyết vấn đề cho tôi.

mytext = soup.get_text(strip=True)

5
strip=Truechỉ hoạt động nếu &nbsp;ở đầu hoặc cuối của mỗi bit văn bản. Nó sẽ không xóa khoảng trắng nếu nó nằm giữa các ký tự khác trong văn bản.
JFS

1

Phiên bản chung với biểu thức chính quy (Nó sẽ xóa tất cả các ký tự điều khiển):

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

-1

Python nhận ra nó giống như một nhân vật không gian, vì vậy bạn có thể làm splitđiều đó mà không cần tranh luận và tham gia bởi một khoảng trắng thông thường:

line = ' '.join(line.split())
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.