cadeia hexadecimal para matriz de bytes em python

150

Eu tenho uma longa seqüência de caracteres hexadecimal que representa uma série de valores de diferentes tipos. Desejo converter esse Hex String em uma matriz de bytes, para que eu possa mudar cada valor e convertê-lo em seu tipo de dados apropriado.

Richard
fonte
Como é a aparência dessa string hexadecimal?
Khachik

Respostas:

239

Suponha que sua string hexadecimal seja algo como

>>> hex_string = "deadbeef"

Converta-o em uma string (Python ≤ 2.7):

>>> hex_data = hex_string.decode("hex")
>>> hex_data
"\xde\xad\xbe\xef"

ou desde Python 2.7 e Python 3.0:

>>> bytes.fromhex(hex_string)  # Python ≥ 3
b'\xde\xad\xbe\xef'

>>> bytearray.fromhex(hex_string)
bytearray(b'\xde\xad\xbe\xef')

Observe que bytesé uma versão imutável do bytearray.

tzot
fonte
27
Se alguém está procurando por hex string-> bytesobjeto, é `bytes.fromhex (" 000102030405060708090A0B0C0D0E0F ")` que gera b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'. Não postando como resposta, já que a pergunta pede matriz de bytes, mas postando aqui, pois é o primeiro hit que recebi ao pesquisar por hext para bytes.
Matrixanomaly 29/07/2015
@Hubro Na verdade, hex_string.decode("hex")está trabalhando no Python 2.7. Acabei de testar no meu Python 2.7.10 (default, May 23 2015, 09:44:00) [MSC v.1500 64 bit (AMD64)] on win32.
MewX
@MewX Eu disse Python 3, não Python 2.7
Hubro
3
Observe que bytes.fromhexgera um erro quando a sequência de entrada possui um número ímpar de caracteres: bytes.fromhex("aab")ValueError: non-hexadecimal number found in fromhex() arg at position 3.
Константин Ван
143

Há uma função interna no bytearray que faz o que você pretende.

bytearray.fromhex("de ad be ef 00")

Retorna um bytearray e lê seqüências hexadecimais com ou sem separador de espaço.

Kugg
fonte
4
A melhor resposta, com certeza!
Maiku Mori
5
Isso funciona no Python 3, enquanto hex_string.decode("hex")que não.
Eric O Lebigot
15

desde que eu entendi corretamente, você deve procurar binascii.unhexlify

import binascii
a='45222e'
s=binascii.unhexlify(a)
b=[ord(x) for x in s]
Bruce
fonte
4
Concordo que unhexlifyé a maneira mais eficiente de ir aqui, mas sugeriria que b = bytearray(s)seria melhor do que usar ord. Como Python tem um built-in tipo apenas para matrizes de bytes Estou surpreso que ninguém o está usando
Scott Griffiths
8

Supondo que você tenha uma sequência de bytes assim

"\ x12 \ x45 \ x00 \ xAB"

e você sabe a quantidade de bytes e seu tipo, você também pode usar essa abordagem

import struct

bytes = '\x12\x45\x00\xAB'
val = struct.unpack('<BBH', bytes)

#val = (18, 69, 43776)

Como especifiquei little endian (usando o caractere '<') no início da string de formato, a função retornou o equivalente decimal.

0x12 = 18

0x45 = 69

0xAB00 = 43776

B é igual a um byte (8 bits) não assinado

H é igual a dois bytes (16 bits) não assinado

Mais caracteres disponíveis e tamanhos de bytes podem ser encontrados aqui

As vantagens são ..

Você pode especificar mais de um byte e o endian dos valores

Desvantagens ..

Você realmente precisa saber o tipo e o comprimento dos dados com os quais está lidando

Hovo
fonte
2
Desvantagens: isso é uma sequência de bytes, não uma sequência hexadecimal, portanto, essa não é uma resposta para a pergunta.
QRIS
É uma resposta para a 2ª parte da pergunta "... para que eu possa mudar cada valor e convertê-lo em seu tipo de dados apropriado".
Rainald62
2

Você deve conseguir construir uma string contendo os dados binários usando algo como:

data = "fef0babe"
bits = ""
for x in xrange(0, len(data), 2)
  bits += chr(int(data[x:x+2], 16))

Provavelmente, essa não é a maneira mais rápida (muitas sequências de caracteres acrescentadas), mas é bastante simples usando apenas o Python principal.

descontrair
fonte
2

Você pode usar o módulo Codecs na biblioteca padrão do Python, ou seja,

import codecs

codecs.decode(hexstring, 'hex_codec')
velsim
fonte
-3
def hex2bin(s):
    hex_table = ['0000', '0001', '0010', '0011',
                 '0100', '0101', '0110', '0111',
                 '1000', '1001', '1010', '1011',
                 '1100', '1101', '1110', '1111']
    bits = ''
    for i in range(len(s)):
        bits += hex_table[int(s[i], base=16)]
    return bits
Dmitry Sobolev
fonte
-4

Um bom liner é:

byte_list = map(ord, hex_string)

Isso irá percorrer cada caractere na string e executá-lo através da função ord (). Testado apenas no python 2.6, não tenho muita certeza sobre o 3.0+.

-Josh

karlw
fonte
perfeito. Trabalhando em python 2.7
Richard
Clique no contorno da marca de seleção ao lado desta resposta, se for a correta! :)
jathanism
1
Isso não converte hexadecimal - converte cada caractere de uma string em um número inteiro. Para hexadecimal, cada par de caracteres representaria um byte. Você pode muito bem dizerbyte_list = bytearray(hex_string)
Scott Griffiths