2012-10-31 22 views
7

Voglio costruire un piccolo formattatore in python darmi indietro le numerici valori incorporati nelle linee di stringhe esadecimali.riordino ordine dei byte nella stringa esadecimale (python)

È una parte centrale del mio programma di formattazione e dovrebbe essere abbastanza veloce per il formato oltre 100 righe/sec (ogni riga circa ~ 100 caratteri).

Il seguente codice dovrebbe dare un esempio in cui sto attualmente bloccato.

'data_string_in_orig' mostra il formato di ingresso. Deve essere byte scambiati per ogni parola. è necessaria Lo swap da 'data_string_in_orig' a ​​ 'data_string_in_swapped'. Alla fine ho bisogno della struttura accesso come mostrato. Il risultato atteso è all'interno del commento.

Grazie in anticipo Wolfgang R

#!/usr/bin/python 

import binascii 
import struct 

## 'uint32 double' 
data_string_in_orig = 'b62e000052e366667a66408d' 
data_string_in_swapped = '2eb60000e3526666667a8d40' 
print data_string_in_orig 

packed_data = binascii.unhexlify(data_string_in_swapped) 
s = struct.Struct('<Id') 
unpacked_data = s.unpack_from(packed_data, 0) 
print 'Unpacked Values:', unpacked_data 

## Unpacked Values: (46638, 943.29999999943209) 

exit(0) 

risposta

13

array.arrays hanno un byteswap method:

import binascii 
import struct 
import array 
x = binascii.unhexlify('b62e000052e366667a66408d') 
y = array.array('h', x) 
y.byteswap() 
s = struct.Struct('<Id') 
print(s.unpack_from(y)) 

# (46638, 943.2999999994321) 

Il h in array.array('h', x) è stato scelto perché dice array.array considerare i dati in x come una matrice di 2 -byte pantaloncini. L'importante è che ogni oggetto sia considerato lungo 2 byte. H, che significa 2 byte unsigned short, funziona altrettanto bene.

+0

'array.byteswap'. Dolce. Immagino che andrò avanti e non postare la kludgy decomprimere la soluzione big-endian/repack little-endian che ho cucinato ... – Triptych

+0

Vai avanti e post! Può essere utile avere più di un modo per risolvere un problema. – unutbu

+1

Grazie, questo è stato veloce e perfetto per me. Tra l'altro 100k linee in 5 sec. –

6

Questo dovrebbe fare esattamente ciò che la versione di unutbu fa, ma potrebbe essere un po 'più facile da seguire per un po' ...

from binascii import unhexlify 
from struct import pack, unpack 
orig = unhexlify('b62e000052e366667a66408d') 
swapped = pack('<6h', *unpack('>6h', orig)) 
print unpack('<Id', swapped) 

# (46638, 943.2999999994321) 

In sostanza, decomprimere 6 pantaloncini big-endian, imballare e 6 cortometraggi little-endian.

Anche in questo caso, la stessa cosa che il codice di unutbu fa, e si dovrebbe usare il suo.

modificare appena realizzato riesco a usare il mio linguaggio Python preferito per questo ... Non fare questo o:

orig = 'b62e000052e366667a66408d' 
swap =''.join(sum([(c,d,a,b) for a,b,c,d in zip(*[iter(orig)]*4)],())) 
# '2eb60000e3526666667a8d40' 
0
import binascii, tkinter, array 
from tkinter import * 

infile_read = filedialog.askopenfilename() 

with open(infile, 'rb') as infile_: 
    infile_read = infile_.read() 

x = (infile_read) 
y = array.array('l', x) 
y.byteswap() 
swapped = (binascii.hexlify(y)) 

Questo è un unsigned short di swap a 32 bit ho realizzato con codice molto molto simile a rispondere solo un po ' "di unutbu" più facile da capire. E tecnicamente binascii non è necessario per lo scambio. è necessaria solo array.byteswap.

0

Lo swap da 'data_string_in_orig' a ​​'data_string_in_swapped' può anche essere fatto con comprensioni senza l'utilizzo di tutte le importazioni:

>>> d = 'b62e000052e366667a66408d' 
>>> "".join([m[2:4]+m[0:2] for m in [d[i:i+4] for i in range(0,len(d),4)]]) 
'2eb60000e3526666667a8d40' 

La comprensione lavora per scambiare l'ordine dei byte nelle stringhe esadecimali che rappresentano parole di 16 bit. Modificandolo per una diversa parola di lunghezza è banale. Possiamo fare una generale funzione di ordine di scambio esadecimale cifre anche:

def swap_order(d, wsz=4, gsz=2): 
    return "".join(["".join([m[i:i+gsz] for i in range(wsz-gsz,-gsz,-gsz)]) for m in [d[i:i+wsz] for i in range(0,len(d),wsz)]]) 

I params ingresso sono:

d: la stringa di input esadecimale

WSZ: la parola-size a nibble (e.g per parole da 16 bit WSZ = 4, per parole di 32 bit WSZ = 8)

GSZ: il numero di nibbles che rimangono insieme (ad esempio per riordinare byte GSZ = 2, per riordinare parole a 16 bit GSZ = 4