2012-10-29 11 views
18

Pracując po jakimś kodzie Pythona, zauważam, że istnieje wiele różnych reprezentacji dla wartości szesnastkowych. Na przykład, jeśli wybiorę numer tak:Różnica między różnymi typami/reprezentacjami heksadecymalnymi w Pythonie

xx = '\x03\xff' 

wówczas następujące polecenia (w wersji z których używam do konwersji trochę endian do big endian)

yy = hex(struct.unpack('>H', xx)[0]) 

powróci:

'0x3ff' 

jednak to polecenie

zz = xx.encode('hex') 

powróci:

'03ff' 

Wreszcie, drukowanie tylko wartość powróci z tej

'\x03\xff' 

Od spojrzeń tego istnieją trzy różne rodzaje hex wtedy.

  1. '\xFF'
  2. '0xFF'
  3. 'FF'

Jaka jest różnica?

punkty bonusowe jeśli ktoś mógłby sugerować lepszy sposób konwertowania mały endian do wielkiej liczby endian. Powyższa metoda dla yy nie będzie działać dla liczb większych niż dwa bajty uparcie i pracuję z pewnymi ciągami heksadecymalnymi o długości 16 bajtów (włączając wartości, które nie odpowiadają wartości ascii/integer)

+0

Numpy ma rutyny, aby pomóc bajt zamawiania http: // docs.scipy.org/doc/numpy/user/basics.byteswapping.html – tpg2114

+0

Pozdrawiam. Popatrzę na to teraz – stephenfin

Odpowiedz

7

Wszystko, co używa \x, jest kodem wyjścia, który używa notacji szesnastkowej; inne kody ucieczkowe obejmują \n dla znaków nowej linii, \' w celu dosłownego cytowania, itd. Ciąg pythona jest ciągiem bajtów i możesz określić wartości literalne poza obszarem drukowania ASCII przy użyciu takich znaków.Kiedy Python echa ciąg znaków z powrotem na ciebie w tłumacza, lub wydrukować jego wynik repr() rozmowy na sznurku, Python będzie korzystać z takich ucieczek reprezentować dowolny bajt, który nie może być wydrukowany jako znak ASCII Zamiast:

>>> chr(65) 
'A' 
>>> chr(11) 
'\x0b' 

Funkcja hex() zwraca bardzo specyficzną reprezentację ciągów znaków, podobnie jak .encode('hex'), z tą różnicą, że pierwsza zawiera prefiks 0x. Istnieją jeszcze dwie metody tworzenia takich reprezentacji ciągów; przy użyciu formaterów ciągów znaków '%x' i '%X', które używają małych lub wielkich liter do reprezentacji.

>>> hex(11) 
'0xb' 
>>> '\x0b'.encode('hex') 
'0b' 
>>> '%x' % (11,) 
'b' 
>>> '%X' % (11,) 
'B' 

Są to wszystkie reprezentacje strunowe chociaż (seria znaków ASCII), i mają taki sam stosunek do oryginalnych danych jako str(number) jest do całkowitych danych; zmieniłeś typ i są bardziej oddalone od celu zmiany kolejności bajtów.

Zmiana fragmentu informacji binarnych z małych końcówek na big-endian wymaga znajomości rozmiaru rozmiaru tej informacji. Jeśli wszystko, co masz, to krótkie liczby całkowite, to musisz odwracać co dwa bajty, ale jeśli masz normalne (długie) liczby całkowite, to masz 4 bajty na wartość i musisz odwrócić każde 4 bajty.

Zastosowanie modułu jest, moim zdaniem, doskonałym podejściem, ponieważ trzeba określić typ wartości. Poniższa zinterpretuje xx jako big-endian unsigned short int, a następnie zapakować je z powrotem do reprezentacji binarnej jako little-endian unsigned short int:

>>> import struct 
>>> xx = '\x03\xff' 
>>> struct.pack('<H', *struct.unpack('>H', xx)) 
'\xff\x03' 
2

„\ xFF” oznacza ciąg znaków zawierający znak o kodzie ASCII 255.

np print '\x41' daje „a” (ponieważ jest to znak ASCII o kodzie 41)

xx.encode('hex') i hex(struct.unpack('>H', xx)[0]) prostu dać człowiekowi czytelna heksadecymalna reprezentacja kodów ASCII zawartych w ciągu xx. Oznacza to, że wynikowy ciąg zawiera liczbę znaków od a do f lub od 0 do 9.