การอ่านอักขระจากไฟล์ใน Python


102

ในไฟล์ข้อความมีสตริง "ฉันไม่ชอบสิ่งนี้"

อย่างไรก็ตามเมื่ออ่านเป็นสตริงมันจะกลายเป็น "I don \ xe2 \ x80 \ x98t แบบนี้" ฉันเข้าใจว่า \ u2018 คือการแสดง Unicode ของ "" " ฉันใช้

f1 = open (file1, "r")
text = f1.read()

คำสั่งในการอ่าน

ตอนนี้เป็นไปได้ไหมที่จะอ่านสตริงในลักษณะที่เมื่ออ่านเป็นสตริงแล้วมันคือ "ฉันไม่ชอบ" แทนที่จะเป็น "ฉันไม่ได้ xe2 \ x80 \ x98t แบบนี้"

การแก้ไขครั้งที่สอง: ฉันเคยเห็นบางคนใช้การแมปเพื่อแก้ปัญหานี้ แต่จริงๆแล้วไม่มีการแปลงในตัวที่ทำให้การแปลง ANSI เป็น Unicode (และในทางกลับกัน) หรือไม่


ความคิดเห็นบางส่วน: ฉันเคยเห็นบางคนใช้การทำแผนที่เพื่อแก้ปัญหานี้ แต่จริงๆแล้วไม่มีการแปลงในตัวที่แปลง ANSI เป็น Unicode (และในทางกลับกัน) หรือไม่ ขอบคุณ!
Graviton

ไม่มีเพราะจุดรหัส Unicode มีหลายแสนจุด คุณจะตัดสินใจได้อย่างไรว่าควรจับคู่กับอักขระ ASCII ตัวใด
John Millikin

2
btw ไฟล์ข้อความของคุณเสีย! U + 2018 คือ "LEFT SINGLE QUOTATION MARK" ไม่ใช่เครื่องหมายอะพอสทรอฟี (U + 0027 โดยทั่วไป)

จอห์นความคิดเห็นของคุณผิดอย่างน้อยก็ในแง่ทั่วไป iconv lib สามารถใช้ในการทับศัพท์อักขระ Unicode เป็น ascii (แม้จะขึ้นอยู่กับภาษา. $ python -c 'print u "\ u2018" .encode ("utf-8")' | iconv -t 'ascii // translit' | xxd 0000000: 270a

สิ่งนี้คือคุณต้องแปลง UNICODE เป็น ASCII (ไม่ใช่วิธีอื่น)
hasen

คำตอบ:


157

อ้างอิง: http://docs.python.org/howto/unicode

การอ่าน Unicode จากไฟล์จึงทำได้ง่าย:

import codecs
with codecs.open('unicode.rst', encoding='utf-8') as f:
    for line in f:
        print repr(line)

นอกจากนี้ยังสามารถเปิดไฟล์ในโหมดอัปเดตซึ่งอนุญาตให้อ่านและเขียนได้:

with codecs.open('test', encoding='utf-8', mode='w+') as f:
    f.write(u'\u4500 blah blah blah\n')
    f.seek(0)
    print repr(f.readline()[:1])

แก้ไข : ฉันสมมติว่าเป้าหมายที่คุณตั้งใจไว้คือเพื่อให้สามารถอ่านไฟล์ได้อย่างถูกต้องเป็นสตริงใน Python หากคุณกำลังพยายามแปลงเป็นสตริง ASCII จาก Unicode ไม่มีวิธีโดยตรงในการทำเช่นนั้นเนื่องจากอักขระ Unicode ไม่จำเป็นต้องมีอยู่ใน ASCII

หากคุณกำลังพยายามแปลงเป็นสตริง ASCII ให้ลองทำอย่างใดอย่างหนึ่งต่อไปนี้:

  1. แทนที่อักขระยูนิโคดที่เฉพาะเจาะจงด้วย ASCII ที่เทียบเท่าหากคุณต้องการจัดการเฉพาะกรณีพิเศษบางอย่างเช่นตัวอย่างนี้

  2. ใช้unicodedataโมดูลnormalize()และstring.encode()วิธีการในการแปลงให้ดีที่สุดเท่าที่จะทำได้เป็น ASCII ที่ใกล้เคียงที่สุดถัดไป (อ้างอิงhttps://web.archive.org/web/20090228203858/http://techxplorer.com/2006/07/18/converting- unicode-to-ascii-using-python ):

    >>> teststr
    u'I don\xe2\x80\x98t like this'
    >>> unicodedata.normalize('NFKD', teststr).encode('ascii', 'ignore')
    'I donat like this'

3
codecsโมดูลไม่สามารถจัดการโหมด newlines สากลได้อย่างเหมาะสม ใช้io.open()แทนบน Python 2.7+ (สร้างขึ้นopen()ใน Python 3)
jfs

15

มีบางจุดที่ต้องพิจารณา

อักขระ \ u2018 อาจปรากฏเป็นเพียงส่วนหนึ่งของการแสดงสตริง Unicode ใน Python เช่นถ้าคุณเขียน:

>>> text = u'‘'
>>> print repr(text)
u'\u2018'

ตอนนี้ถ้าคุณต้องการพิมพ์สตริง Unicode อย่างสวยงามเพียงใช้encodeวิธีการของ Unicode :

>>> text = u'I don\u2018t like this'
>>> print text.encode('utf-8')
I dont like this

เพื่อให้แน่ใจว่าทุกบรรทัดจากไฟล์ใด ๆ จะถูกอ่านเป็น Unicode คุณควรใช้codecs.openฟังก์ชันนี้แทนที่จะเป็นเพียงแค่openซึ่งช่วยให้คุณระบุการเข้ารหัสของไฟล์:

>>> import codecs
>>> f1 = codecs.open(file1, "r", "utf-8")
>>> text = f1.read()
>>> print type(text)
<type 'unicode'>
>>> print text.encode('utf-8')
I dont like this

6

แต่จริงๆแล้ว "ฉันไม่ชอบสิ่งนี้" ไม่ใช่ "ฉันไม่ชอบสิ่งนี้" อักขระ u "\ u2018" เป็นอักขระที่แตกต่างไปจาก "" "โดยสิ้นเชิง (และตามภาพควรตรงกับ" "" มากกว่า)

หากคุณกำลังพยายามแปลง Unicode ที่เข้ารหัสเป็น ASCII แบบธรรมดาคุณอาจใช้เครื่องหมายวรรคตอนแบบ Unicode ที่ต้องการแปลเป็น ASCII

punctuation = {
  u'\u2018': "'",
  u'\u2019': "'",
}
for src, dest in punctuation.iteritems():
  text = text.replace(src, dest)

อย่างไรก็ตามมีอักขระเครื่องหมายวรรคตอนที่น่ากลัวจำนวนมากใน Unicodeแต่ฉันคิดว่าคุณสามารถวางใจได้ว่ามีเพียงไม่กี่ตัวเท่านั้นที่ใช้โดยแอปพลิเคชันใดก็ตามที่สร้างเอกสารที่คุณกำลังอ่านอยู่


1
ที่จริงแล้วถ้าคุณสร้างไดอะล็อกบ็อกซ์ Unicode แมปไปยังลำดับ Unicode ({0x2018: 0x27, 0x2019: 0x27}) คุณก็สามารถส่งคำสั่งทั้งหมดไปยัง text.translate () เพื่อทำการแทนที่ทั้งหมดในครั้งเดียว
Thomas Wouters

5

นอกจากนี้ยังสามารถอ่านไฟล์ข้อความที่เข้ารหัสโดยใช้วิธีการอ่าน python 3:

f = open (file.txt, 'r', encoding='utf-8')
text = f.read()
f.close()

ด้วยรูปแบบนี้ไม่จำเป็นต้องนำเข้าไลบรารีเพิ่มเติมใด ๆ


3

ทิ้งความจริงที่ว่าไฟล์ข้อความของคุณเสีย (U + 2018 เป็นเครื่องหมายคำพูดด้านซ้ายไม่ใช่เครื่องหมายวรรคตอน): iconv สามารถใช้ทับศัพท์อักขระ Unicode เป็น ascii ได้

คุณจะต้อง Google สำหรับ "iconvcodec" เนื่องจากดูเหมือนว่าโมดูลจะไม่ได้รับการสนับสนุนอีกต่อไปและฉันไม่พบหน้าแรกที่เป็นมาตรฐานสำหรับมัน

>>> import iconvcodec
>>> from locale import setlocale, LC_ALL
>>> setlocale(LC_ALL, '')
>>> u'\u2018'.encode('ascii//translit')
"'"

หรือคุณสามารถใช้iconvยูทิลิตี้บรรทัดคำสั่งเพื่อล้างไฟล์ของคุณ:

$ xxd foo
0000000: e280 980a                                ....
$ iconv -t 'ascii//translit' foo | xxd
0000000: 270a                                     '.

2

มีความเป็นไปได้ที่คุณจะมีสตริงที่ไม่ใช่ Unicode ที่มีอักขระหลีกเลี่ยง Unicode เช่น:

>>> print repr(text)
'I don\\u2018t like this'

เรื่องนี้เคยเกิดขึ้นกับฉันมาแล้วครั้งหนึ่ง คุณสามารถใช้unicode_escapeตัวแปลงสัญญาณเพื่อถอดรหัสสตริงเป็น Unicode จากนั้นเข้ารหัสเป็นรูปแบบใดก็ได้ที่คุณต้องการ:

>>> uni = text.decode('unicode_escape')
>>> print type(uni)
<type 'unicode'>
>>> print uni.encode('utf-8')
I dont like this

1

นี่คือวิธี Pythons ที่แสดงสตริงที่เข้ารหัสแบบ Unicode แต่ฉันคิดว่าคุณน่าจะสามารถพิมพ์สตริงบนหน้าจอหรือเขียนลงในไฟล์ใหม่ได้โดยไม่มีปัญหา

>>> test = u"I don\u2018t like this"
>>> test
u'I don\u2018t like this'
>>> print test
I dont like this

1

ที่จริงแล้ว U + 2018 คือการแสดง Unicode ของอักขระพิเศษ ' หากคุณต้องการคุณสามารถแปลงอินสแตนซ์ของอักขระนั้นเป็น U + 0027 ด้วยรหัสนี้:

text = text.replace (u"\u2018", "'")

นอกจากนี้คุณใช้อะไรในการเขียนไฟล์? f1.read()ควรส่งคืนสตริงที่มีลักษณะดังนี้:

'I don\xe2\x80\x98t like this'

หากส่งคืนสตริงนี้แสดงว่าไฟล์ถูกเขียนอย่างไม่ถูกต้อง:

'I don\u2018t like this'

ขออภัย! อย่างที่คุณพูดมันกำลังส่งคืน 'ฉันไม่ xe2 \ x80 \ x98t แบบนี้'
Graviton

'ฉันไม่ได้ xe2 \ x80 \ x98t แบบนี้' ที่คุณเห็นคือสิ่งที่ Python เรียกว่า str ดูเหมือนว่าจะเป็นการเข้ารหัส utf-8 ของ u'I don \ u2018t like this 'ซึ่งเป็นอินสแตนซ์ Unicode ใน Python ลองเรียก. decode ('utf-8') ที่หลังหรือ. encode ('utf-8')
Logan

@hop: โอ๊ะโอลืม ord () คืนค่าทศนิยมแทนฐานสิบหก ขอบคุณสำหรับการจับ
John Millikin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.