바이트 문자열을 정수로 변환하는 방법은 무엇입니까?


162

파이썬에서 바이트 문자열을 int로 어떻게 변환 할 수 있습니까?

이렇게 말하십시오 : 'y\xcc\xa6\xbb'

나는 영리하고 어리석은 방법을 생각해 냈습니다.

sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))

나는 이것을 더 간단하게하는 내장 또는 표준 라이브러리에 무언가가 있어야한다는 것을 알고있다 ...

이것은 int (xxx, 16)를 사용할 수있는 16 진수 문자열을 변환하는 것과 다르지만 대신 실제 바이트 값의 문자열을 변환하려고합니다.

최신 정보:

나는 다른 모듈을 가져올 필요가 없기 때문에 James의 대답이 조금 나아졌지 만 Greg의 방법이 더 빠릅니다.

>>> 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

내 해키 방법 :

>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit()
2.8819329738616943

추가 업데이트 :

누군가 다른 모듈을 가져 오는 데 어떤 문제가 있는지 의견을 물었습니다. 글쎄, 모듈을 임포트하는 것이 반드시 싼 것은 아닙니다.

>>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit()
0.98822188377380371

모듈을 가져 오는 비용을 포함 시키면이 방법이 갖는 거의 모든 이점이 무시됩니다. 여기에는 전체 벤치 마크 실행시 한 번만 가져 오는 비용이 포함된다고 생각합니다. 매번 다시로드 할 때 어떤 일이 발생하는지보십시오.

>>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit()
68.474128007888794

말할 필요도없이, 한 번의 가져 오기 마다이 방법을 많이 실행하면 이보다 비례 적으로 덜 문제가됩니다. CPU가 아닌 i / o 비용 일 수 있으므로 특정 머신의 용량 및로드 특성에 따라 달라질 수 있습니다.


표준 라이브러리에서 무언가를 가져 오는 것이 좋지 않습니다. 왜 그렇습니까?


26
"추가 업데이트"가 이상합니다. 왜 모듈을 이렇게 자주 가져 옵니까?

5
나는 이것이 오래된 질문이라는 것을 안다. 그러나 다른 사람들에 대한 비교를 최신 상태로 유지하려면 내 컴퓨터에서 기계 달팽이의 답변 ( int.from_bytes)이 성능을 초과했습니다 struct.unpack. 더 읽기 쉬운 imo 옆에 있습니다.
magu_

답변:


110

struct 모듈을 사용하여 이를 수행 할 수도 있습니다 .

>>> struct.unpack("<L", "y\xcc\xa6\xbb")[0]
3148270713L

3
경고 : "L"은 64 비트 Python 빌드에서 실제로 8 바이트 (4가 아님)이므로 실패 할 수 있습니다.
Rafał Dowgird

12
Rafał : Greg가 <를 사용하고 있었기 때문에 문서에 따르면 L은 표준 크기 (4)입니다. "포맷 문자열이 '<', '>', '!'중 하나로 시작하는 경우 또는 '='. " docs.python.org/library/struct.html#format-characters
André Laszlo

59
이 답변은 임의 길이의 이진 문자열에는 작동하지 않습니다.
amcnabb

4
유형에는 특정 크기가 있으며 임의 길이의 이진 문자열에는 작동하지 않습니다. 각 항목의 유형을 알고있는 경우 처리하도록 for 루프를 설정할 수 있습니다.
Joshua Olson

2
"L"은 실제로 uint32 (4 바이트)입니다. 필자의 경우 8 바이트가 필요하면 "Q"-> uint64를 사용하십시오. "l"-> int32 및 q-> int64
ntg

319

Python 3.2 이상에서

>>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='big')
2043455163

또는

>>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='little')
3148270713

바이트 문자열 의 엔디안 에 따라 .

이것은 또한 임의의 길이의 바이트 문자열-정수 및을 지정하여 2의 보수 부호있는 정수에 대해서도 작동합니다 signed=True. 에 대한 문서를from_bytes 참조하십시오 .


@eri 얼마나 느려? struct를 사용했지만 py3에 갔을 때 int.from_bytes로 변환했습니다. 직렬 데이터를 수신 할 때 마다이 메소드를 매 ms마다 호출하므로 속도 향상을 환영합니다. 나는 이것을보고있다
Naib

@Naib, os.urandom(4)내 CPU의 바이트 ** 1.4 µs ** (struct) vs ** 2.3 µs ** (int.from_bytes)의 경우. python 3.5.2
eri December

5
@eri 나는 몇 가지 CRC 방법을 평가하는 데 사용한 timeit 스크립트를 부활시켰다. 4 개의 실행 1) struct 2) int.from_bytes 3) # 1이지만 cython 컴파일, 4) # 2와 같지만 cython 컴파일. 구조체의 경우 330ns, int의 경우 1.14us (사이 토론은 두 가지 모두 20ns의 속도 향상을주었습니다 ...)는 다시 전환하는 것처럼 보입니다. -가공하고 부품을 떨어 뜨 렸습니다.
Naib

66

Greg가 말했듯이 이진 값을 처리하는 경우 struct를 사용할 수 있지만 "16 진수"만 있고 바이트 형식이면 다음과 같이 변환 할 수 있습니다.

s = 'y\xcc\xa6\xbb'
num = int(s.encode('hex'), 16)

... 이것은 다음과 같습니다 :

num = struct.unpack(">L", s)[0]

... 모든 바이트에서 작동한다는 점을 제외하고.


3
"이진 값"과 "'16 진수"이지만 바이트 형식 "의 차이점은 정확히 무엇입니까 ???????

"도움말 구조"를 참조하십시오. 예 : "001122334455".decode ( 'hex')는 struct를 사용하여 숫자로 변환 할 수 없습니다.
James Antill

3
그런데이 대답은 정수가 빅 엔디안 바이트 순서로 인코딩되어 있다고 가정합니다. 리틀 엔디안 주문의 경우 :int(''.join(reversed(s)).encode('hex'), 16)
amcnabb

1
좋지만 이것은 느려질 것입니다! 파이썬으로 코딩하고 있다면 그것은 중요하지 않습니다.
MattCochrane 5

8

다음 함수를 사용하여 int, hex 및 bytes 사이의 데이터를 변환합니다.

def bytes2int(str):
 return int(str.encode('hex'), 16)

def bytes2hex(str):
 return '0x'+str.encode('hex')

def int2bytes(i):
 h = int2hex(i)
 return hex2bytes(h)

def int2hex(i):
 return hex(i)

def hex2int(h):
 if len(h) > 1 and h[0:2] == '0x':
  h = h[2:]

 if len(h) % 2:
  h = "0" + h

 return int(h, 16)

def hex2bytes(h):
 if len(h) > 1 and h[0:2] == '0x':
  h = h[2:]

 if len(h) % 2:
  h = "0" + h

 return h.decode('hex')

출처 : http://opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html


6
import array
integerValue = array.array("I", 'y\xcc\xa6\xbb')[0]

경고 : 위의 내용은 플랫폼에 따라 다릅니다. "I"지정자와 문자열-> int 변환의 엔디안은 모두 특정 Python 구현에 따라 다릅니다. 그러나 한 번에 많은 정수 / 문자열을 변환하려면 배열 모듈이 빠르게 수행합니다.


5

Python 2.x에서는 형식 지정자를 사용할 수 있습니다 <B 부호없는 <b바이트와 struct.unpack/를 부호있는 바이트에 를struct.pack .

예 :

허락하다 x ='\xff\x10\x11'

data_ints = struct.unpack('<' + 'B'*len(x), x) # [255, 16, 17]

과:

data_bytes = struct.pack('<' + 'B'*len(data_ints), *data_ints) # '\xff\x10\x11'

* 필요합니다!

보다 형식 지정자 목록은 https://docs.python.org/2/library/struct.html#format-characters참조하십시오 .


3
>>> reduce(lambda s, x: s*256 + x, bytearray("y\xcc\xa6\xbb"))
2043455163

테스트 1 : 역 :

>>> hex(2043455163)
'0x79cca6bb'

테스트 2 : 바이트 수> 8

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAA"))
338822822454978555838225329091068225L

테스트 3 : 하나씩 증가

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAB"))
338822822454978555838225329091068226L

테스트 4 : 1 바이트 추가, 'A':

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA"))
86738642548474510294585684247313465921L

테스트 5 : 256으로 나누기 :

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA"))/256
338822822454978555838225329091068226L

결과는 예상대로 시험 4의 결과와 같습니다.


1

파이썬 2.x에서 작동하는 임의의 길이 바이트 시퀀스에 대한 솔루션을 찾기 위해 고심하고있었습니다. 마지막 으로이 것을 썼습니다. 문자열 변환을 수행하기 때문에 약간 해킹이지만 작동합니다.

Python 2.x 용 함수, 임의 길이

def signedbytes(data):
    """Convert a bytearray into an integer, considering the first bit as
    sign. The data must be big-endian."""
    negative = data[0] & 0x80 > 0

    if negative:
        inverted = bytearray(~d % 256 for d in data)
        return -signedbytes(inverted) - 1

    encoded = str(data).encode('hex')
    return int(encoded, 16)

이 기능에는 두 가지 요구 사항이 있습니다.

  • 입력 data은이어야합니다 bytearray. 다음과 같이 함수를 호출 할 수 있습니다.

    s = 'y\xcc\xa6\xbb'
    n = signedbytes(s)
  • 데이터는 빅 엔디안이어야합니다. 리틀 엔디안 값이있는 경우 먼저 되돌려 야합니다.

    n = signedbytes(s[::-1])

물론 이것은 임의의 길이가 필요한 경우에만 사용해야합니다. 그렇지 않으면보다 표준적인 방법을 사용하십시오 (예 :) struct.


1

> = 3.2 버전 인 경우 int.from_bytes가 최상의 솔루션입니다. "struct.unpack"솔루션에는 문자열이 필요하므로 바이트 배열에는 적용되지 않습니다. 또 다른 해결책은 다음과 같습니다.

def bytes2int( tb, order='big'):
    if order == 'big': seq=[0,1,2,3]
    elif order == 'little': seq=[3,2,1,0]
    i = 0
    for j in seq: i = (i<<8)+tb[j]
    return i

hex (bytes2int ([0x87, 0x65, 0x43, 0x21]))는 '0x87654321'을 반환합니다.

크고 작은 엔디안을 처리하며 8 바이트로 쉽게 수정할 수 있습니다.


1

위에서 언급했듯이 구조체의unpack 기능을 사용 하는 것이 좋습니다. 자신의 기능을 구현하려면 다른 해결책이 있습니다.

def bytes_to_int(bytes):
    result = 0
    for b in bytes:
        result = result * 256 + int(b)
return result

바이트로 변환 된 음수에는 작동하지 않습니다.
Maria

1

파이썬 3에서는 바이트 문자열을 다음과 같이 정수 (0..255) 목록으로 쉽게 변환 할 수 있습니다

>>> list(b'y\xcc\xa6\xbb')
[121, 204, 166, 187]

0

한동안 사용했던 array.array를 사용하는 매우 빠른 방법 :

사전 정의 된 변수 :

offset = 0
size = 4
big = True # endian
arr = array('B')
arr.fromstring("\x00\x00\xff\x00") # 5 bytes (encoding issues) [0, 0, 195, 191, 0]

int : (읽기)

val = 0
for v in arr[offset:offset+size][::pow(-1,not big)]: val = (val<<8)|v

int에서 : (쓰기)

val = 16384
arr[offset:offset+size] = \
    array('B',((val>>(i<<3))&255 for i in range(size)))[::pow(-1,not big)]

그래도 더 빠를 수도 있습니다.

편집 :
일부 숫자의 경우 다음과 비교하여 읽을 때 안정적인 평균을 보여주는 성능 테스트 (Anaconda 2.3.0)가 있습니다 reduce().

========================= byte array to int.py =========================
5000 iterations; threshold of min + 5000ns:
______________________________________code___|_______min______|_______max______|_______avg______|_efficiency
⣿⠀⠀⠀⠀⡇⢀⡀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⡀⠀⢰⠀⠀⠀⢰⠀⠀⠀⢸⠀⠀⢀⡇⠀⢀⠀⠀⠀⠀⢠⠀⠀⠀⠀⢰⠀⠀⠀⢸⡀⠀⠀⠀⢸⠀⡇⠀⠀⢠⠀⢰⠀⢸⠀
⣿⣦⣴⣰⣦⣿⣾⣧⣤⣷⣦⣤⣶⣾⣿⣦⣼⣶⣷⣶⣸⣴⣤⣀⣾⣾⣄⣤⣾⡆⣾⣿⣿⣶⣾⣾⣶⣿⣤⣾⣤⣤⣴⣼⣾⣼⣴⣤⣼⣷⣆⣴⣴⣿⣾⣷⣧⣶⣼⣴⣿⣶⣿⣶
    val = 0 \nfor v in arr: val = (val<<8)|v |     5373.848ns |   850009.965ns |     ~8649.64ns |  62.128%
⡇⠀⠀⢀⠀⠀⠀⡇⠀⡇⠀⠀⣠⠀⣿⠀⠀⠀⠀⡀⠀⠀⡆⠀⡆⢰⠀⠀⡆⠀⡄⠀⠀⠀⢠⢀⣼⠀⠀⡇⣠⣸⣤⡇⠀⡆⢸⠀⠀⠀⠀⢠⠀⢠⣿⠀⠀⢠⠀⠀⢸⢠⠀⡀
⣧⣶⣶⣾⣶⣷⣴⣿⣾⡇⣤⣶⣿⣸⣿⣶⣶⣶⣶⣧⣷⣼⣷⣷⣷⣿⣦⣴⣧⣄⣷⣠⣷⣶⣾⣸⣿⣶⣶⣷⣿⣿⣿⣷⣧⣷⣼⣦⣶⣾⣿⣾⣼⣿⣿⣶⣶⣼⣦⣼⣾⣿⣶⣷
                  val = reduce( shift, arr ) |     6489.921ns |  5094212.014ns |   ~12040.269ns |  53.902%

이것은 원시 성능 테스트이므로 엔디 언 포탄 플립은 제외됩니다.
표시된 shift함수는 for 루프와 동일한 시프트 오더 연산을 적용하며, 그 옆에서 가장 빠른 반복 성능을 갖는 arr것과 array.array('B',[0,0,255,0])같습니다dict .

또한 효율성은 평균 시간의 정확도로 측정됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.