2011-08-08 39 views
8

Khi Python 3k giới thiệu sự phân biệt nghiêm ngặt giữa các chuỗi và byte, các đối số dòng lệnh trong mảng sys.argv được trình bày dưới dạng chuỗi. Đôi khi, cần phải coi các đối số là byte, ví dụ: khi đi qua một đường dẫn không cần phải có trong bất kỳ mã hóa ký tự cụ thể nào trong Unix.sys.argv dưới dạng byte trong Python 3k

Hãy xem ví dụ. Sơ lược Python 3k chương trình argv.py sau:

đầu ra
import sys 

print(sys.argv[1]) 
print(b'bytes') 

Khi nó được thực hiện như python3.1 argv.py français nó tạo ra mong đợi:

français

b'bytes'

Lưu ý rằng đối số français là trong bảng mã miền địa phương của tôi. Tuy nhiên, khi chúng ta vượt qua đối số trong một bảng mã khác nhau chúng ta có được một lỗi: python3.1 argv.py `echo français|iconv -t latin1`

Traceback (most recent call last): 
    File "argv.py", line 3, in <module> 
    print(sys.argv[1]) 
    UnicodeEncodeError: 'utf-8' codec can't encode character '\udce7' in position 4: surrogates not allowed 

Làm thế nào chúng ta sẽ truyền dữ liệu nhị phân để chương trình Python 3k qua đối số dòng lệnh? Một ví dụ về cách sử dụng là chuyển một đường dẫn đến tệp của người dùng sử dụng ngôn ngữ khác.

+1

Vấn đề mã hóa đánh lừa các câu trả lời, tôi đề xuất một "python3 argv.py \" echo -ne "\ xff \ x80 \ x00" \ '' là một ví dụ về «truyền dữ liệu nhị phân qua các đối số dòng lệnh» – Nope

Trả lời

2

Bạn có thể làm:

sys.argv[1].encode() hoặc, nếu bạn biết được mã hóa sử dụng nó như là đối số hoặc gọi bytes(sys.argv[1], 'latin-1').

Cả hai đều sẽ cho bạn biểu diễn byte của chuỗi unicode.

Theo mặc định, Python3 sử dụng UTF-8.

+2

Không, Python không nhất thiết sử dụng UTF8, nó phụ thuộc vào nền tảng. –

+2

@Lennart Python 3 sử dụng UTF-8 làm mã hóa mặc định. – JBernardo

+2

Không, nó không đơn giản như vậy. Mã hóa mặc định cho thiết bị đầu cuối không nhất thiết là UTF-8 và không phải là mã hóa mặc định cho các hệ thống tệp.Tôi trích dẫn "Có một mã hóa mặc định phụ thuộc vào nền tảng, mà trên nền tảng Unixy có thể được thiết lập với biến môi trường LANG (và đôi khi cũng với một số biến môi trường liên quan đến ngôn ngữ cụ thể khác của nền tảng). Trong nhiều trường hợp, nhưng không phải tất cả, mặc định hệ thống là UTF-8; bạn sẽ không bao giờ được tính vào mặc định này. " Đó là trong thực tế cp1252 đó là mặc định trên Windows. Mặc định cho các tệp .py là UTF8. –

8

Lưu ý rằng lỗi là UnicodeEncodeError thay vì UnicodeDecodeError. Python bảo toàn các byte chính xác được truyền trên dòng lệnh (thông qua bộ xử lý lỗi PEP 383 surrogateescape), nhưng các byte đó không hợp lệ UTF-8 và do đó không thể mã hóa như vậy để ghi vào bàn điều khiển.

Cách tốt nhất để đối phó với điều này là sử dụng những kiến ​​thức mức ứng dụng của mã hóa chính xác để diễn giải lại các đối số dòng lệnh bên trong ứng dụng, như trong đoạn mã ví dụ sau:

$ python3.2 -c "import os, sys; print(os.fsencode(sys.argv[1]).decode('latin-1'))" `echo français|iconv -t latin1` 
français 

Các os.fsencode chức năng gọi đảo ngược chuyển đổi Python được áp dụng tự động khi xử lý các đối số dòng lệnh. Cuộc gọi phương thức decode('latin-1') sau đó thực hiện chuyển đổi chính xác để nhận chuỗi được giải mã đúng.

os.fsencode đã được thêm vào bằng Python 3.2, đặc biệt để làm cho loại vấn đề này dễ giải quyết hơn. Đối với Python 3.1, các cấu trúc tương đương cho os.fsencode(sys.argv[1])sys.argv[1].encode(sts.getfilesystemencoding(), 'surrogateescape')

Sửa Tháng 2 năm 2013: cập nhật cho Python 3.2+, và để tránh giả định rằng Python autodetected "UTF-8" như mã hóa dòng lệnh

+0

Bạn không thể giả định rằng ngôn ngữ là UTF-8. Vì vậy, bạn phải mã hóa bằng cách sử dụng mã hóa hệ thống tập tin: sys.argv [1] .encode (sys.getfilesystemencoding(), 'surrogateescape') giải mã ('latin-1') – mhagger

+2

Thật vậy. Mặc dù, trong Python 3.3, việc sử dụng 'os.fsencode' thậm chí còn dễ dàng hơn. Tôi cũng đã đệ trình một lỗi, lưu ý rằng các tài liệu sys.argv nên thực sự giải thích điểm này. – ncoghlan

Các vấn đề liên quan