Membaca karakter dari file dengan Python

102

Di file teks, ada string "Saya tidak suka ini".

Namun, ketika saya membacanya menjadi string, itu menjadi "Saya tidak \ xe2 \ x80 \ x98t seperti ini". Saya memahami bahwa \ u2018 adalah representasi unicode dari "'". saya menggunakan

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

perintah untuk melakukan pembacaan.

Sekarang, apakah mungkin untuk membaca string sedemikian rupa sehingga ketika dibaca menjadi string, menjadi "Saya tidak suka ini", bukan "Saya tidak \ xe2 \ x80 \ x98t seperti ini"?

Pengeditan kedua: Saya telah melihat beberapa orang menggunakan pemetaan untuk memecahkan masalah ini, tetapi sungguh, apakah tidak ada konversi bawaan yang melakukan konversi semacam ANSI ke unicode (dan sebaliknya) ini?

Graviton
sumber
Beberapa komentar: Saya telah melihat beberapa orang menggunakan pemetaan untuk memecahkan masalah ini, tetapi sungguh, apakah tidak ada konversi bawaan yang melakukan konversi semacam ANSI ke unicode (dan sebaliknya) ini? Terima kasih!
Graviton
Tidak ada, karena ada ratusan ribu titik kode Unicode. Bagaimana Anda memutuskan mana yang harus dipetakan ke karakter ASCII apa?
John Millikin
2
btw, file teks Anda rusak! U + 2018 adalah "LEFT SINGLE QUOTATION MARK", bukan apostrof (U + 0027 paling umum).
John, komentar Anda salah, setidaknya dalam arti umum. lib iconv dapat digunakan untuk mentransliterasi karakter unicode ke ascii (bahkan bergantung pada lokal. $ python -c 'print u "\ u2018" .encode ("utf-8")' | iconv -t 'ascii // translit' | xxd 0000000: 270a
masalahnya, Anda perlu mengubah UNICODE ke ASCII (bukan sebaliknya).
hasen

Jawaban:

157

Ref: http://docs.python.org/howto/unicode

Karena itu, membaca Unicode dari file sangatlah sederhana:

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

Anda juga dapat membuka file dalam mode pembaruan, memungkinkan membaca dan menulis:

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])

EDIT : Saya berasumsi bahwa tujuan yang Anda maksudkan hanyalah untuk dapat membaca file dengan benar menjadi string dengan Python. Jika Anda mencoba mengonversi ke string ASCII dari Unicode, maka tidak ada cara langsung untuk melakukannya, karena karakter Unicode belum tentu ada di ASCII.

Jika Anda mencoba mengonversi ke string ASCII, coba salah satu dari berikut ini:

  1. Ganti karakter unicode tertentu dengan yang setara dengan ASCII, jika Anda hanya ingin menangani beberapa kasus khusus seperti contoh khusus ini

  2. Gunakan unicodedatamodul normalize()dan string.encode()metode untuk mengkonversi sebaik mungkin ke ASCII terdekat berikutnya yang setara (Ref 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'
Jay
sumber
3
codecsmodul tidak menangani mode baris baru universal dengan benar. Gunakan io.open()sebagai gantinya pada Python 2.7+ (ini dibangun open()pada Python 3).
jfs
15

Ada beberapa hal yang perlu diperhatikan.

Karakter \ u2018 hanya dapat muncul sebagai fragmen representasi string unicode di Python, misalnya jika Anda menulis:

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

Sekarang jika Anda hanya ingin mencetak string unicode dengan rapi, cukup gunakan encodemetode unicode :

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

Untuk memastikan bahwa setiap baris dari file mana pun akan dibaca sebagai unicode, Anda sebaiknya menggunakan codecs.openfungsi daripada hanya open, yang memungkinkan Anda menentukan pengkodean file:

>>> 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
DzinX
sumber
6

Tapi yang sebenarnya adalah "Saya tidak suka ini" dan bukan "Saya tidak suka ini". Karakter u '\ u2018' adalah karakter yang sama sekali berbeda dari "'" (dan, secara visual, harus lebih sesuai dengan' ``).

Jika Anda mencoba mengonversi unicode yang dikodekan menjadi ASCII biasa, Anda mungkin dapat menyimpan pemetaan tanda baca unicode yang ingin Anda terjemahkan ke dalam ASCII.

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

Ada banyak sekali karakter tanda baca dalam unicode , namun, saya kira Anda hanya dapat mengandalkan beberapa dari mereka yang benar-benar digunakan oleh aplikasi apa pun yang membuat dokumen yang Anda baca.

Logan
sumber
1
sebenarnya, jika Anda membuat dict memetakan ordinal Unicode ke ordinal Unicode ({0x2018: 0x27, 0x2019: 0x27}), Anda cukup meneruskan seluruh dict ke text.translate () untuk melakukan semua penggantian sekaligus.
Thomas Wouters
5

Dimungkinkan juga untuk membaca file teks yang disandikan menggunakan metode baca python 3:

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

Dengan variasi ini, tidak perlu mengimpor pustaka tambahan

Gelas bir
sumber
3

Mengesampingkan fakta bahwa file teks Anda rusak (U + 2018 adalah tanda kutip kiri, bukan apostrof): iconv dapat digunakan untuk mentransliterasi karakter unicode ke ascii.

Anda harus menggunakan Google untuk "iconvcodec", karena modul tersebut tampaknya tidak lagi didukung dan saya tidak dapat menemukan beranda kanonisnya.

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

Atau Anda dapat menggunakan iconvutilitas baris perintah untuk membersihkan file Anda:

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

sumber
2

Ada kemungkinan bahwa entah bagaimana Anda memiliki string non-unicode dengan karakter escape unicode, misalnya:

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

Ini benar-benar pernah terjadi pada saya sebelumnya. Anda dapat menggunakan unicode_escapecodec untuk memecahkan kode string menjadi unicode dan kemudian menyandikannya ke format apa pun yang Anda inginkan:

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

Ini adalah cara Pythons yang menunjukkan kepada Anda string yang dikodekan unicode. Tetapi saya pikir Anda harus dapat mencetak string di layar atau menuliskannya menjadi file baru tanpa masalah.

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

Sebenarnya U + 2018 adalah representasi Unicode dari karakter khusus '. Jika mau, Anda dapat mengonversi karakter tersebut menjadi U + 0027 dengan kode ini:

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

Selain itu, apa yang Anda gunakan untuk menulis file? f1.read()harus mengembalikan string yang terlihat seperti ini:

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

Jika mengembalikan string ini , file salah ditulis:

'I don\u2018t like this'
John Millikin
sumber
Maaf! Seperti yang Anda katakan, ini mengembalikan 'Saya tidak \ xe2 \ x80 \ x98t seperti ini'
Graviton
'Saya tidak \ xe2 \ x80 \ x98t seperti ini' yang Anda lihat adalah apa yang Python sebut sebagai str. Tampaknya ini adalah pengkodean utf-8 dari u'I don \ u2018t like this ', yang merupakan instance unicode dengan Python. Coba panggil .decode ('utf-8') pada yang pertama atau .encode ('utf-8') pada yang terakhir.
Logan
@ hop: oops, lupa ord () mengembalikan desimal, bukan hex. Terima kasih atas tangkapannya.
John Millikin