275

Tôi bị suy não khi đọc và viết văn bản vào một tệp (Python 2.4).

# The string, which has an a-acute in it.
ss = u'Capit\xe1n'
ss8 = ss.encode('utf8')
repr(ss), repr(ss8)

("u'Capit \ xe1n '", "' Capit \ xc3 \ xa1n '")

print ss, ss8
print >> open('f1','w'), ss8

>>> file('f1').read()
'Capit\xc3\xa1n\n'

Vì vậy, tôi gõ Capit\xc3\xa1nvào trình soạn thảo yêu thích của tôi, trong tệp f2.

Sau đó:

>>> open('f1').read()
'Capit\xc3\xa1n\n'
>>> open('f2').read()
'Capit\\xc3\\xa1n\n'
>>> open('f1').read().decode('utf8')
u'Capit\xe1n\n'
>>> open('f2').read().decode('utf8')
u'Capit\\xc3\\xa1n\n'

Tôi không hiểu gì ở đây? Rõ ràng có một số phép thuật quan trọng (hoặc ý nghĩa tốt) mà tôi đang thiếu. Điều gì làm một loại vào các tệp văn bản để có được chuyển đổi phù hợp?

Điều tôi thực sự thất bại ở đây, đó là điểm của đại diện UTF-8 là gì, nếu bạn thực sự không thể khiến Python nhận ra nó, khi nó đến từ bên ngoài. Có lẽ tôi chỉ nên kết xuất chuỗi JSON và sử dụng chuỗi đó thay vào đó, vì nó có đại diện đáng tin cậy! Hơn nữa, có một đại diện ASCII của đối tượng Unicode này mà Python sẽ nhận ra và giải mã, khi đến từ một tệp không? Nếu vậy, làm thế nào để tôi có được nó?

>>> print simplejson.dumps(ss)
'"Capit\u00e1n"'
>>> print >> file('f3','w'), simplejson.dumps(ss)
>>> simplejson.load(open('f3'))
u'Capit\xe1n'
|
97

Trong ký hiệu

u'Capit\xe1n\n'

"\ xe1" chỉ đại diện cho một byte. "\ x" cho bạn biết rằng "e1" ở dạng thập lục phân. Khi bạn viết

Capit\xc3\xa1n

vào tập tin của bạn, bạn có "\ xc3" trong đó. Đó là 4 byte và trong mã của bạn, bạn đọc tất cả. Bạn có thể thấy điều này khi bạn hiển thị chúng:

>>> open('f2').read()
'Capit\\xc3\\xa1n\n'

Bạn có thể thấy dấu gạch chéo ngược được thoát bằng dấu gạch chéo ngược. Vì vậy, bạn có bốn byte trong chuỗi của mình: "\", "x", "c" và "3".

Chỉnh sửa:

Như những người khác đã chỉ ra trong câu trả lời của họ, bạn chỉ cần nhập các ký tự trong trình chỉnh sửa và sau đó trình soạn thảo của bạn sẽ xử lý việc chuyển đổi sang UTF-8 và lưu nó.

Nếu bạn thực sự có một chuỗi ở định dạng này, bạn có thể sử dụng string_escapecodec để giải mã nó thành một chuỗi bình thường:

In [15]: print 'Capit\\xc3\\xa1n\n'.decode('string_escape')
Capitán

Kết quả là một chuỗi được mã hóa bằng UTF-8 trong đó ký tự có dấu được biểu thị bằng hai byte được ghi \\xc3\\xa1trong chuỗi gốc. Nếu bạn muốn có một chuỗi unicode, bạn phải giải mã lại bằng UTF-8.

Để chỉnh sửa của bạn: bạn không có UTF-8 trong tệp của mình. Để thực sự thấy nó trông như thế nào:

s = u'Capit\xe1n\n'
sutf8 = s.encode('UTF-8')
open('utf-8.out', 'w').write(sutf8)

So sánh nội dung của tệp utf-8.outvới nội dung của tệp bạn đã lưu với trình chỉnh sửa của mình.

|
  • 1

    Vì vậy, điểm của định dạng được mã hóa utf-8 là gì nếu python có thể đọc trong các tệp bằng cách sử dụng nó? Nói cách khác, có đại diện ascii nào mà python sẽ đọc trong \ xc3 dưới dạng 1 byte không?

    – Hồ Hoàng Duy 16:51:22 29/01/2009
  • 1

    Câu trả lời cho câu hỏi "Vì vậy, câu hỏi điểm" là gì "Mu." (vì Python có thể đọc các tệp được mã hóa trong UTF-8). Đối với câu hỏi thứ hai của bạn: \ xc3 không phải là một phần của bộ ASCII. Có lẽ bạn có nghĩa là "mã hóa 8 bit" thay vào đó. Bạn đang bối rối về Unicode và mã hóa; không sao đâu, nhiều rồi

    – Thương Mại Thông Minh 12:16:16 30/01/2009
  • 1

    Hãy thử đọc phần này dưới dạng mồi: joelonsoftware.com/articles/Unicode.html

    – Hoàng Tuấn Dũng 12:16:54 30/01/2009
  • 1

    lưu ý: u'\xe1'là một mã điểm Unicode U+00e1có thể được biểu diễn bằng 1 hoặc nhiều byte tùy theo mã hóa ký tự (nó là 2 byte trong utf-8). b'\xe1'là một byte (một số 225), những gì thư nếu có nó có thể đại diện phụ thuộc vào mã hóa ký tự dùng để giải mã nó ví dụ, đó là б( U+0431) trong CP1251, с( U+0441) trong cp866 vv

    – Bùi Thanh Ðoàn 06:31:15 15/06/2013
  • 1

    Thật đáng ngạc nhiên khi nhiều lập trình viên người Anh nói "chỉ sử dụng ascii" và sau đó không nhận ra rằng dấu £ không phải là nó. Hầu hết không biết rằng ascii! = Trang mã địa phương (tức là latin1).

    – Lý Hàm Thơ 12:58:58 05/09/2013
648

Thay vì lộn xộn với các phương thức mã hóa và giải mã, tôi thấy việc chỉ định mã hóa dễ dàng hơn khi mở tệp. Các iomô-đun (được thêm vào trong Python 2.6) cung cấp một io.openchức năng, trong đó có một tham số mã hóa.

Sử dụng phương pháp mở từ iomô-đun.

>>>import io
>>>f = io.open("test", mode="r", encoding="utf-8")

Sau đó, sau khi gọi hàm read () của f, một đối tượng Unicode được mã hóa được trả về.

>>>f.read()
u'Capit\xe1l\n\n'

Lưu ý rằng trong Python 3, io.openhàm là bí danh cho openhàm tích hợp. Hàm mở tích hợp chỉ hỗ trợ đối số mã hóa trong Python 3, không phải Python 2.

Chỉnh sửa: Trước đây câu trả lời này đã đề xuất mô-đun codec . Các mô-đun codec có thể gây ra vấn đề khi trộn read()readline() , vì vậy câu trả lời này ngay bây giờ đề nghị các io mô-đun để thay thế.

Sử dụng phương pháp mở từ mô-đun codec.

>>>import codecs
>>>f = codecs.open("test", "r", "utf-8")

Sau đó, sau khi gọi hàm read () của f, một đối tượng Unicode được mã hóa được trả về.

>>>f.read()
u'Capit\xe1l\n\n'

Nếu bạn biết mã hóa một tập tin, sử dụng gói codec sẽ ít gây nhầm lẫn hơn.

Xem http://docs.python.org/l Library / codecs.html # codecs.open

|
  • 1

    Hoạt động hoàn hảo cho các văn bản file quá, thay vì open(file,'w')làm codecs.open(file,'w','utf-8')giải quyết

    – Hồ Hoàng Duy 02:12:27 04/03/2011
  • 1

    Liệu codecs.open(...)phương pháp này cũng hoàn toàn phù hợp với with open(...):phong cách, nơi withquan tâm về việc đóng tệp sau khi tất cả được thực hiện? Dường như nó hoạt động.

    – Thương Mại Thông Minh 18:09:26 04/03/2013
  • 1

    @ thử-bắt-cuối cùng Có. Tôi sử dụng with codecs.open(...) as f:tất cả thời gian.

    – Hoàng Tuấn Dũng 14:27:37 08/07/2013
  • 1

    Tôi ước tôi có thể nâng cao điều này hàng trăm lần. Sau khi đau đớn trong vài ngày về các vấn đề mã hóa gây ra bởi nhiều dữ liệu hỗn hợp và đọc lướt qua về mã hóa, câu trả lời này giống như nước trong sa mạc. Ước gì tôi nhìn thấy nó sớm hơn.

    – Bùi Thanh Ðoàn 18:24:23 21/07/2013
  • 1

    Điều này nên được chấp nhận câu trả lời :)

    – Lý Hàm Thơ 08:08:25 20/07/2015
28

Bây giờ tất cả những gì bạn cần trong Python3 là open(Filename, 'r', encoding='utf-8')

[Chỉnh sửa vào ngày 2016 / 02-10 để làm rõ yêu cầu]

Python3 đã thêm tham số mã hóa vào hàm mở của nó. Thông tin sau đây về chức năng mở được thu thập từ đây: https://docs.python.org/3/l Library / fiances.html # open

open(file, mode='r', buffering=-1, 
      encoding=None, errors=None, newline=None, 
      closefd=True, opener=None)

Mã hóa là tên của mã hóa được sử dụng để giải mã hoặc mã hóa tệp. Điều này chỉ nên được sử dụng trong chế độ văn bản. Mã hóa mặc định phụ thuộc vào nền tảng (bất cứ thứ gì trả về locale.getpreferredencoding () ), nhưng bất kỳ mã hóa văn bản nào được Python hỗ trợ đều có thể được sử dụng. Xem các codec mô-đun để biết danh sách các mã hóa được hỗ trợ.

Vì vậy, bằng cách thêm encoding='utf-8'làm tham số cho hàm mở, việc đọc và ghi tệp hoàn toàn được thực hiện dưới dạng utf8 (hiện cũng là mã hóa mặc định của mọi thứ được thực hiện trong Python.)

|
17

Vì vậy, tôi đã tìm thấy một giải pháp cho những gì tôi đang tìm kiếm, đó là:

print open('f2').read().decode('string-escape').decode("utf-8")

Có một số codec bất thường hữu ích ở đây. Cách đọc đặc biệt này cho phép một người lấy các biểu diễn UTF-8 từ bên trong Python, sao chép chúng vào tệp ASCII và để chúng được đọc thành Unicode. Theo giải mã "thoát chuỗi", dấu gạch chéo sẽ không được nhân đôi.

Điều này cho phép loại chuyến đi khứ hồi mà tôi đang tưởng tượng.

|
  • 1

    Phản hồi tốt, tôi đã được thử nghiệm cả hai giải pháp (codecs.open(file,"r","utf-8")và đơn giản open(file,"r").read().decode("utf-8")và cả hai đều hoạt động hoàn hảo.

    – Phâu Phin 09:03:48 13/06/2013
  • 1

    Tôi đang nhận được một "TypeError: đối tượng str, byte hoặc os.PathLike dự kiến, không phải là _io.TextIOWrapper" tại sao?

    – Võ Vạn Thông 21:37:04 07/01/2017
  • 1

    Tôi nghĩ rằng, xem xét số lượng upvote, sẽ là một ý tưởng tuyệt vời để chấp nhận câu trả lời thứ hai :)

    – Huỳnh Nhã Khanh 12:00:39 04/04/2017
14

Trên thực tế, điều này làm việc cho tôi khi đọc một tệp có mã hóa UTF-8 trong Python 3.2:

import codecs
f = codecs.open('file_name.txt', 'r', 'UTF-8')
for line in f:
    print(line)
|
14
# -*- encoding: utf-8 -*-

# converting a unknown formatting file in utf-8

import codecs
import commands

file_location = "jumper.sub"
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location)

file_stream = codecs.open(file_location, 'r', file_encoding)
file_output = codecs.open(file_location+"b", 'w', 'utf-8')

for l in file_stream:
    file_output.write(l)

file_stream.close()
file_output.close()
|
6

ngoại trừ codecs.open(), người ta có thể sử dụng io.open()để làm việc với Python2 hoặc Python3 để đọc / ghi tệp unicode

thí dụ

import io

text = u'á'
encoding = 'utf8'

with io.open('data.txt', 'w', encoding=encoding, newline='\n') as fout:
    fout.write(text)

with io.open('data.txt', 'r', encoding=encoding, newline='\n') as fin:
    text2 = fin.read()

assert text == text2
|
6

Bạn đã vấp phải vấn đề chung với mã hóa: Làm thế nào tôi có thể biết mã hóa tệp là gì?

Trả lời: Bạn không thể trừ khi định dạng tệp cung cấp cho việc này. XML, ví dụ, bắt đầu bằng:

<?xml encoding="utf-8"?>

Tiêu đề này đã được chọn cẩn thận để nó có thể được đọc bất kể mã hóa. Trong trường hợp của bạn, không có gợi ý nào như vậy, do đó cả biên tập viên và Python của bạn đều không biết chuyện gì đang xảy ra. Do đó, bạn phải sử dụng codecsmô-đun và sử dụng codecs.open(path,mode,encoding)cung cấp bit bị thiếu trong Python.

Đối với trình soạn thảo của bạn, bạn phải kiểm tra xem nó có cung cấp một số cách để đặt mã hóa tệp không.

Quan điểm của UTF-8 là có thể mã hóa các ký tự 21 bit (Unicode) dưới dạng luồng dữ liệu 8 bit (vì đó là điều duy nhất mà tất cả các máy tính trên thế giới có thể xử lý). Nhưng vì hầu hết các hệ điều hành trước thời đại Unicode, chúng không có các công cụ phù hợp để đính kèm thông tin mã hóa vào các tệp trên đĩa cứng.

Vấn đề tiếp theo là sự đại diện trong Python. Điều này được giải thích hoàn hảo trong bình luận của heikogerlach . Bạn phải hiểu rằng bảng điều khiển của bạn chỉ có thể hiển thị ASCII. Để hiển thị Unicode hoặc bất cứ thứ gì> = charcode 128, nó phải sử dụng một số phương tiện để thoát. Trong trình chỉnh sửa của bạn, bạn không được nhập chuỗi hiển thị đã thoát nhưng chuỗi đó có nghĩa là gì (trong trường hợp này, bạn phải nhập ô và lưu tệp).

Điều đó nói rằng, bạn có thể sử dụng hàm Python eval () để biến một chuỗi thoát thành chuỗi:

>>> x = eval("'Capit\\xc3\\xa1n\\n'")
>>> x
'Capit\xc3\xa1n\n'
>>> x[5]
'\xc3'
>>> len(x[5])
1

Như bạn có thể thấy, chuỗi "\ xc3" đã được biến thành một ký tự. Đây là một chuỗi 8 bit, được mã hóa UTF-8. Để có được Unicode:

>>> x.decode('utf-8')
u'Capit\xe1n\n'

Gregg Lind hỏi: Tôi nghĩ có một số phần bị thiếu ở đây: tệp f2 chứa: hex:

0000000: 4361 7069 745c 7863 335c 7861 316e  Capit\xc3\xa1n

codecs.open('f2','rb', 'utf-8'), ví dụ, đọc tất cả chúng trong một ký tự riêng (dự kiến) Có cách nào để ghi vào một tệp trong ASCII sẽ hoạt động không?

Trả lời: Điều đó phụ thuộc vào ý của bạn. ASCII không thể biểu thị các ký tự> 127. Vì vậy, bạn cần một số cách để nói "một vài ký tự tiếp theo có nghĩa là một cái gì đó đặc biệt", đó là những gì chuỗi "\ x" làm. Nó nói: Hai ký tự tiếp theo là mã của một ký tự. "\ u" thực hiện tương tự bằng cách sử dụng bốn ký tự để mã hóa Unicode lên đến 0xFFFF (65535).

Vì vậy, bạn không thể trực tiếp viết Unicode sang ASCII (vì ASCII đơn giản là không chứa cùng các ký tự). Bạn có thể viết nó dưới dạng chuỗi thoát (như trong f2); trong trường hợp này, tệp có thể được biểu diễn dưới dạng ASCII. Hoặc bạn có thể viết nó dưới dạng UTF-8, trong trường hợp đó, bạn cần một luồng an toàn 8 bit.

Giải pháp của bạn sử dụng decode('string-escape')không hoạt động, nhưng bạn phải nhận thức được bạn sử dụng bao nhiêu bộ nhớ: Ba lần lượng sử dụng codecs.open().

Hãy nhớ rằng một tệp chỉ là một chuỗi byte có 8 bit. Cả bit và byte đều không có nghĩa. Chính bạn là người nói "65 có nghĩa là" A ". \xc3\xa1sẽ trở thành "à" nhưng máy tính không có phương tiện để biết, bạn phải nói với nó bằng cách chỉ định mã hóa được sử dụng khi ghi tệp.

|
  • 1

    Tôi nghĩ rằng có một số phần bị thiếu ở đây: tệp f2 chứa: hex: 0000000: 4361 7069 745c 7863 335c 7861 316e 0a Capit \ xc3 \ xa1n. codecs.open ('f2', 'rb', 'utf-8'), ví dụ, đọc tất cả chúng trong một ký tự riêng (dự kiến) Có cách nào để ghi vào tệp trong ascii sẽ hoạt động không?

    – Phâu Phin 17:21:07 29/01/2009
6

Để đọc trong một chuỗi Unicode và sau đó gửi tới HTML, tôi đã làm điều này:

fileline.decode("utf-8").encode('ascii', 'xmlcharrefreplace')

Hữu ích cho các máy chủ http hỗ trợ python.

|
5

Chà, trình soạn thảo văn bản yêu thích của bạn không nhận ra rằng nó \xc3\xa1được coi là chữ nhân vật, nhưng nó diễn giải chúng thành văn bản. Đó là lý do tại sao bạn nhận được dấu gạch chéo kép ở dòng cuối cùng - giờ đây là dấu gạch chéo ngược thực sự +xc3 , v.v. trong tệp của bạn.

Nếu bạn muốn đọc và ghi các tệp được mã hóa bằng Python, tốt nhất nên sử dụng codec mô-đun .

Việc dán văn bản giữa thiết bị đầu cuối và các ứng dụng rất khó khăn, vì bạn không biết chương trình nào sẽ diễn giải văn bản của bạn bằng cách sử dụng mã hóa nào. Bạn có thể thử như sau:

>>> s = file("f1").read()
>>> print unicode(s, "Latin-1")
Capitán

Sau đó dán chuỗi này vào trình soạn thảo của bạn và đảm bảo rằng nó lưu chuỗi đó bằng Latin-1. Theo giả định rằng bảng tạm không cắt xén chuỗi, chuyến đi khứ hồi sẽ hoạt động.

|
4

Chuỗi \ x .. là một cái gì đó đặc trưng cho Python. Đây không phải là một chuỗi thoát byte phổ quát.

Cách bạn thực sự nhập vào UTF-8 được mã hóa không phải ASCII tùy thuộc vào HĐH và / hoặc trình soạn thảo của bạn. Đây là cách bạn làm điều đó trong Windows . Đối với OS X để nhập một với dấu sắc bạn chỉ có thể nhấn option+ E, sau đó A, và hầu như tất cả soạn thảo văn bản trong OS X hỗ trợ UTF-8.

|
3

Bạn cũng có thể cải thiện open()chức năng ban đầu để làm việc với các tệp Unicode bằng cách thay thế nó tại chỗ, sử dụng partialchức năng. Cái hay của giải pháp này là bạn không cần thay đổi bất kỳ mã cũ nào. Nó trong suốt.

import codecs
import functools
open = functools.partial(codecs.open, encoding='utf-8')
|
1

Tôi đã cố phân tích iCal bằng Python 2.7.9:

từ Lịch nhập icalWiki

Nhưng tôi đã nhận được:

 Traceback (most recent call last):
 File "ical.py", line 92, in parse
    print "{}".format(e[attr])
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 7: ordinal not in range(128)

và nó đã được sửa chỉ với:

print "{}".format(e[attr].encode("utf-8"))

(Bây giờ nó có thể in likeé á böss.)

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.