2011-08-08 4 views
8

Jako że Python 3k wprowadza ścisłe rozróżnienie między łańcuchami i bajtami, argumenty linii poleceń w tablicy sys.argv są przedstawiane jako łańcuchy. Czasami konieczne jest traktowanie argumentów jako bajtów, np. podczas przekazywania ścieżki, która nie musi być w żadnym określonym kodowaniu znaków w systemie Unix.sys.argv jako bajty w Pythonie 3k

Zobaczmy przykład. Krótka Python 3k Program argv.py następująco:

import sys 

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

Gdy jest wykonywany jako python3.1 argv.py français produkuje oczekiwany wynik:

français

b'bytes'

Należy zauważyć, że argument français jest w moim kodowania locale. Jednak, gdy mijamy argumentu w innym kodowaniu otrzymujemy błąd: 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 

Jak możemy przekazać dane binarne do Pythona programu 3k za pośrednictwem argumentów wiersza poleceń? Przykładem użycia jest podanie ścieżki do pliku użytkownika, który używa innych ustawień narodowych.

+1

Kwestia kodowania wprowadzić w błąd odpowiedzi, proponuję 'python3 argv.py \ echo -ne" \ xff \ x80 \ x00 "\" który jest przykładem "przekazywania danych binarnych za pośrednictwem argumentów linii poleceń" – Nope

Odpowiedz

2

można zrobić:

sys.argv[1].encode() lub, jeśli wiesz, że kodowanie go używać jako argumentu lub zadzwoń bytes(sys.argv[1], 'latin-1').

Obie powinny dawać bajtową reprezentację ciągu znaków Unicode.

Domyślnie Python3 używa UTF-8.

+2

Nie, Python niekoniecznie użyj UTF8, to zależy od platformy. –

+2

@Lennart Python 3 używa kodowania UTF-8 jako domyślnego. – JBernardo

+2

Nie, to nie takie proste. Domyślne kodowanie dla terminali niekoniecznie oznacza kodowanie UTF-8 i nie jest to domyślne kodowanie dla systemów plików.Cytuję: "Istnieje domyślne kodowanie zależne od platformy, które na platformach Unixy można ustawić za pomocą zmiennej środowiskowej LANG (a czasami także z innymi zmiennymi środowiskowymi związanymi z ustawieniami specyficznymi dla danej platformy) .W wielu przypadkach, ale nie we wszystkich, domyślny system to UTF-8, nigdy nie powinieneś liczyć na tę wartość domyślną. " Jest to w rzeczywistości cp1252, który jest domyślny w systemie Windows. Domyślnie dla plików .py jest jednak UTF8. –

8

Należy zauważyć, że błąd jest raczej następujący: UnicodeEncodeError niż UnicodeDecodeError. Python zachowuje dokładne bajty przekazywane w wierszu poleceń (za pośrednictwem procedury obsługi błędów PEP 383 surrogateescape), ale te bajty nie są poprawne w formacie UTF-8 i dlatego nie mogą być zakodowane jako takie do zapisu na konsoli.

Najlepszym sposobem radzenia sobie z tym jest, aby wykorzystać wiedzę poziomie aplikacji prawidłowego kodowania reinterpretacji argument wiersza poleceń wewnątrz aplikacji, jak w poniższym przykładzie kodu:

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

The os.fsencode wywołania funkcji odwraca transformację Python jest stosowany automatycznie podczas przetwarzania argumentów wiersza poleceń. Wywołanie metody decode('latin-1') następnie przeprowadza poprawną konwersję w celu uzyskania poprawnie zdekodowanego ciągu.

os.fsencode został dodany w Pythonie 3.2, w szczególności, aby ułatwić rozwiązywanie tego rodzaju problemu. Dla Pythona 3.1, odpowiednik dla os.fsencode(sys.argv[1]) konstrukt jest sys.argv[1].encode(sts.getfilesystemencoding(), 'surrogateescape')

Edit lutego 2013: zaktualizowane dla Pythona 3.2 lub nowszym, i aby uniknąć zakładając, że Python automatycznie wykrywany „UTF-8” jako kodowanie linii poleceń

+0

Nie można założyć, że locale to UTF-8. Dlatego musisz kodować używając kodowania systemu plików: sys.argv [1] .encode (sys.getfilesystemencoding(), "surrogateescape"). Decode ('latin-1') – mhagger

+2

Rzeczywiście. Chociaż w Pythonie 3.3 użycie 'os.fsencode' jest jeszcze łatwiejsze. Złożyłem również błąd, zauważając, że dokumenty sys.argv powinny wyjaśnić ten punkt. – ncoghlan