Comment puis-je convertir une chaîne d'octets en un entier en python?
Dis comme ça: 'y\xcc\xa6\xbb'
J'ai trouvé une façon intelligente / stupide de le faire:
sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))
Je sais qu'il doit y avoir quelque chose de intégré ou dans la bibliothèque standard qui fait cela plus simplement ...
Ceci est différent de la conversion d'une chaîne de chiffres hexadécimaux pour laquelle vous pouvez utiliser int (xxx, 16), mais je souhaite plutôt convertir une chaîne de valeurs d'octets réelles.
METTRE À JOUR:
J'aime un peu mieux la réponse de James car elle ne nécessite pas d'importer un autre module, mais la méthode de Greg est plus rapide:
>>> from timeit import Timer
>>> Timer('struct.unpack("<L", "y\xcc\xa6\xbb")[0]', 'import struct').timeit()
0.36242198944091797
>>> Timer("int('y\xcc\xa6\xbb'.encode('hex'), 16)").timeit()
1.1432669162750244
Ma méthode hacky:
>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit()
2.8819329738616943
AUTRE MISE À JOUR:
Quelqu'un a demandé dans les commentaires quel était le problème lors de l'importation d'un autre module. Eh bien, importer un module n'est pas forcément bon marché, jetez un œil:
>>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit()
0.98822188377380371
Le fait d'inclure le coût d'importation du module annule presque tous les avantages de cette méthode. Je pense que cela n'inclura que les frais de son importation une fois pour toute la période de référence; regardez ce qui se passe quand je le force à se recharger à chaque fois:
>>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit()
68.474128007888794
Inutile de dire que si vous effectuez beaucoup d'exécutions de cette méthode par importation, cela devient proportionnellement moins problématique. C'est aussi probablement un coût d'E / S plutôt qu'un CPU, donc cela peut dépendre de la capacité et des caractéristiques de charge de la machine particulière.
int.from_bytes
) a surpasséstruct.unpack
sur mon ordinateur. En plus d'être plus lisible imo.Réponses:
Vous pouvez également utiliser le module struct pour ce faire:
la source
Dans Python 3.2 et versions ultérieures, utilisez
ou
selon l' endianness de votre chaîne d'octets.
Cela fonctionne également pour les entiers de chaînes d'octets de longueur arbitraire, et pour les entiers signés complémentaires à deux en spécifiant
signed=True
. Consultez la documentation pourfrom_bytes
.la source
os.urandom(4)
octets ** 1,4 µs ** (struct) vs ** 2,3 µs ** (int.from_bytes) sur mon processeur. python 3.5.2Comme Greg l'a dit, vous pouvez utiliser struct si vous avez affaire à des valeurs binaires, mais si vous avez juste un "nombre hexadécimal" mais au format octet, vous voudrez peut-être simplement le convertir comme:
... c'est la même chose que:
... sauf que cela fonctionnera pour n'importe quel nombre d'octets.
la source
int(''.join(reversed(s)).encode('hex'), 16)
J'utilise la fonction suivante pour convertir les données entre int, hex et octets.
Source: http://opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html
la source
Attention: ce qui précède est fortement spécifique à la plateforme. Le spécificateur "I" et l'endianness de la conversion string-> int dépendent de votre implémentation Python particulière. Mais si vous souhaitez convertir plusieurs entiers / chaînes à la fois, le module de tableau le fait rapidement.
la source
Dans Python 2.x, vous pouvez utiliser les spécificateurs de format
<B
pour les octets non signés et<b
pour les octets signés avecstruct.unpack
/struct.pack
.Par exemple:
Soit
x
='\xff\x10\x11'
Et:
C'est
*
nécessaire!Voir https://docs.python.org/2/library/struct.html#format-characters pour une liste des spécificateurs de format.
la source
Test 1: inverse:
Test 2: Nombre d'octets> 8:
Test 3: incrémenter de un:
Test 4: ajoutez un octet, dites «A»:
Test 5: Diviser par 256:
Le résultat est égal au résultat du test 4, comme prévu.
la source
J'avais du mal à trouver une solution pour les séquences d'octets de longueur arbitraire qui fonctionneraient sous Python 2.x. Enfin j'ai écrit celui-ci, c'est un peu piraté car il effectue une conversion de chaîne, mais ça marche.
Fonction pour Python 2.x, longueur arbitraire
Cette fonction a deux exigences:
L'entrée
data
doit être unbytearray
. Vous pouvez appeler la fonction comme ceci:Les données doivent être big-endian. Si vous avez une valeur petit-boutiste, vous devez d'abord l'inverser:
Bien sûr, cela ne doit être utilisé que si une longueur arbitraire est nécessaire. Sinon, tenez-vous-en à des méthodes plus standard (par exemple
struct
).la source
int.from_bytes est la meilleure solution si vous êtes à la version> = 3.2. La solution "struct.unpack" nécessite une chaîne donc elle ne s'appliquera pas aux tableaux d'octets. Voici une autre solution:
hex (bytes2int ([0x87, 0x65, 0x43, 0x21])) renvoie «0x87654321».
Il gère grand et petit endianness et est facilement modifiable pour 8 octets
la source
Comme mentionné ci-dessus, l'utilisation de la
unpack
fonction de struct est un bon moyen. Si vous souhaitez implémenter votre propre fonction, il existe une autre solution:la source
En python 3, vous pouvez facilement convertir une chaîne d'octets en une liste d'entiers (0..255) en
la source
Une méthode décemment rapide utilisant array.array que j'utilise depuis un certain temps:
variables prédéfinies:
à int: (lire)
from int: (écrire)
Il est possible que cela soit plus rapide.
EDIT:
Pour certains chiffres, voici un test de performance (Anaconda 2.3.0) montrant des moyennes stables en lecture par rapport à
reduce()
:Ceci est un test de performance brut, donc le pow-flip endian est laissé de côté.
La
shift
fonction illustrée applique la même opération de changement de vitesse que la boucle for, etarr
est exactementarray.array('B',[0,0,255,0])
comme elle a les performances itératives les plus rapides à côté dedict
.Je devrais probablement aussi noter que l'efficacité se mesure par la précision au temps moyen.
la source