2013-05-14 25 views
19

Trong khi chuyển mã từ Python 2 sang Python 3, tôi gặp phải vấn đề này khi đọc văn bản UTF-8 từ đầu vào tiêu chuẩn. Trong Python 2, điều này hoạt động tốt:Python 3: Cách chỉ định mã hóa stdin

for line in sys.stdin: 
    ... 

Nhưng Python 3 hy vọng ASCII từ sys.stdin, và nếu có ký tự ASCII trong đầu vào, tôi nhận được lỗi:

UnicodeDecodeError: 'ascii' codec can't decode byte .. in position ..: ordinal not in range(128)

Đối với một tệp thông thường, tôi sẽ chỉ định mã hóa khi mở tệp:

with open('filename', 'r', encoding='utf-8') as file: 
    for line in file: 
     ... 

Nhưng làm cách nào tôi có thể chỉ định mã hóa cho đầu vào chuẩn? Các bài đăng SO khác đã đề xuất sử dụng

input_stream = codecs.getreader('utf-8')(sys.stdin) 
for line in input_stream: 
    ... 

Tuy nhiên, điều này không hoạt động trong Python 3. Tôi vẫn nhận được thông báo lỗi tương tự. Tôi đang sử dụng Ubuntu 12.04.2 và miền địa phương của tôi được đặt thành en_US.UTF-8.

Trả lời

35

Python 3 không không mong ASCII từ sys.stdin. Nó sẽ mở ra stdin ở chế độ văn bản và thực hiện dự đoán có giáo dục về việc sử dụng mã hóa nào. Dự đoán đó có thể giảm xuống còn ASCII, nhưng đó không phải là một giả định. Xem sys.stdin documentation về cách chọn codec.

Giống như các đối tượng tệp khác được mở ở chế độ văn bản, đối tượng sys.stdin có nguồn gốc từ io.TextIOBase base class; nó có thuộc tính .buffer trỏ đến thể hiện IO đệm bên dưới (lần lượt có thuộc tính .raw).

sys.stdin.buffer thuộc tính trong một mới io.TextIOWrapper() instance để xác định một mã hóa khác nhau:

import io 
import sys 

input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') 

Ngoài ra, thiết lập các PYTHONIOENCODING environment variable để các codec mong muốn khi chạy python.

+0

Cảm ơn, điều này đã làm được điều này! –

+2

Tương đương gần nhất cho python2.6 là gì? – bukzor

+1

@bukzor: Tùy chọn tiếp theo: mở bộ mô tả tệp trực tiếp bằng 'io.open()'; '0' là' stdin': 'io.open (0)' trả về một đối tượng 'TextIOWrapper()'. –