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()ดูเหมือนว่าจะทำให้มันคายออกแม้ตัวละคร Weirder \ xc2 เช่น มีใครอธิบายเรื่องนี้ได้บ้าง


ได้ลองแล้วว่าตัวแปลงสัญญาณ 'ascii' ไม่สามารถถอดรหัสไบต์ 0xa0 ในตำแหน่ง 0: เลขลำดับไม่อยู่ในช่วง (128)
zhuyxn

15
โอบกอด Unicode ใช้u''s แทน''s :-)
jpaugh

1
ลองใช้ str.replace (u '\ xa0', '') แต่ได้ "u" s ทุกที่แทน \ xa0s: /
zhuyxn

หากสตริงเป็น Unicode หนึ่งคุณต้องใช้ทดแทนไม่ได้u' ' ' 'สตริงเดิมเป็น unicode หรือไม่
pepr

คำตอบ:


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.n ปกติizeจะเหมาะสมกว่า 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 ชั่วโมงและแก้ไขได้ในที่สุด ขอบคุณมาก.
Sadman Hasan

217

มีสิ่งที่มีประโยชน์มากมายในunicodedataห้องสมุดของ Python หนึ่งในนั้นคือ.normalize()ฟังก์ชั่น

ลอง:

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

การเปลี่ยน NFKD ด้วยวิธีการอื่น ๆ ที่ระบุไว้ในลิงก์ด้านบนหากคุณไม่ได้ผลลัพธ์ที่ต้องการ


9
มันยอดเยี่ยม นี่ควรเป็นคำตอบที่ยอมรับได้
Houman

2
เห็นด้วยอย่างสิ้นเชิง. ง่ายชัดเจนสั้นและตรงประเด็น ยกนิ้ว
Billy Jhon

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 ที่มีอาร์กิวเมนต์แถบเป็น 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 คือสิ่งที่ฉันคอยดูแล
Vasim

12

ลองนี้:

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

5
@RyanMartin: นี้แทนสี่ไบต์ : แต่len(b'\\xa0') == 4 len(b'\xa0') == 1ถ้าเป็นไปได้; คุณควรแก้ไขต้นน้ำที่สร้างทางหนีเหล่านี้
jfs

12

ฉันพบปัญหาเดียวกันนี้ในการดึงข้อมูลบางอย่างจากฐานข้อมูล sqlite3 กับ python คำตอบข้างต้นไม่ได้ผลสำหรับฉัน (ไม่แน่ใจว่าทำไม) แต่สิ่งนี้ทำ:line = line.decode('ascii', 'ignore')อย่างไรก็ตามเป้าหมายของฉันคือการลบ \ xa0s แทนที่จะแทนที่ด้วยช่องว่าง

ฉันได้รับสิ่งนี้จากบทช่วยสอน Unicode ที่เป็นประโยชน์โดย Ned Batchelder


14
ตอนนี้คุณกำลังลบสิ่งที่ไม่ใช่อักขระ ASCII คุณอาจปกปิดปัญหาจริงของคุณ การใช้งาน'ignore'เป็นเหมือนการผลักคันเกียร์แม้ว่าคุณจะไม่เข้าใจว่าคลัทช์ทำงานอย่างไร ..
Martijn Pieters

@MartijnPieters เชื่อมโยง Unicode กวดวิชาเป็นสิ่งที่ดี แต่คุณถูกต้องสมบูรณ์ - str.encode(..., 'ignore')เป็น Unicode try: ... except: ...จัดการเทียบเท่า ในขณะที่มันอาจซ่อนข้อความแสดงข้อผิดพลาดก็ไม่ค่อยแก้ปัญหา
dbr

1
สำหรับวัตถุประสงค์บางอย่างเช่นการจัดการกับ EMAIL หรือ URL ดูเหมือนว่าสมบูรณ์แบบที่จะใช้.decode('ascii', 'ignore')
andilabs

1
คำตอบของ samwizeไม่ได้ผลสำหรับคุณเพราะมันใช้กับUnicode strings line.decode()ในคำตอบของคุณแสดงให้เห็นว่าการป้อนข้อมูลของคุณเป็นbytestring (คุณไม่ควรโทรหา.decode()Unicode string (ในการบังคับใช้วิธีการจะถูกลบใน Python 3) ฉันไม่เข้าใจว่าคุณจะเห็นการกวดวิชาที่เป็นไปได้อย่างไร เชื่อมโยงในคำตอบของคุณและพลาดความแตกต่างระหว่างไบต์และ Unicode (อย่าผสม)
jfs

8

ฉันสิ้นสุดที่นี่ในขณะที่ googling สำหรับปัญหากับตัวละครที่ไม่สามารถพิมพ์ได้ ฉันใช้ MySQLUTF-8 general_ciและจัดการกับภาษาโปแลนด์ สำหรับสตริงที่มีปัญหาฉันต้อง procced ดังนี้

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

เป็นวิธีแก้ปัญหาที่รวดเร็วและคุณน่าจะลองใช้บางอย่างด้วยการตั้งค่าการเข้ารหัสที่ถูกต้อง


1
มันจะทำงานถ้าtextเป็น bytestring ที่แสดงถึงข้อความที่เข้ารหัสโดยใช้ utf-8 หากคุณกำลังทำงานกับข้อความ ถอดรหัสเป็น Unicode ก่อน ( .decode('utf-8')) และเข้ารหัสเป็น bytestring ที่ส่วนท้ายสุดเท่านั้น (หาก API ไม่รองรับ Unicode โดยตรงเช่น, socket) การดำเนินการระหว่างกลางทั้งหมดในข้อความควรดำเนินการใน Unicode
jfs


4

0xA0 (Unicode) คือ 0xC2A0 ใน UTF-8 .encode('utf8')จะใช้ Unicode 0xA0 ของคุณและแทนที่ด้วย 0xC2A0 ของ UTF-8 ดังนั้นการประจักษ์ของ 0xC2s ... การเข้ารหัสไม่ได้แทนที่อย่างที่คุณอาจจะรู้ในตอนนี้


1
0xc2a0ไม่ชัดเจน (สั่งเป็นไบต์) ใช้b'\xc2\xa0'ไบต์ตามตัวอักษรแทน
jfs

3

มันเท่ากับตัวอักษรเว้นวรรคดังนั้นดึงมันออกมา

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

1

ใน Beautiful Soup คุณสามารถส่งget_text()พารามิเตอร์แถบซึ่งตัดช่องว่างจากจุดเริ่มต้นและจุดสิ้นสุดของข้อความ สิ่งนี้จะลบ\xa0หรือเว้นวรรคอื่น ๆ หากเกิดขึ้นที่จุดเริ่มต้นหรือจุดสิ้นสุดของสตริง ซุปสวย ๆ แทนที่สตริงว่างด้วย\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())
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.