बाइट्स की स्ट्रिंग को इंट में कैसे बदलें?


162

मैं अजगर में एक बाइट्स के एक स्ट्रिंग को इंट में कैसे बदल सकता हूं?

इस तरह कहें: 'y\xcc\xa6\xbb'

मैं इसे करने का एक चतुर / मूर्ख तरीका लेकर आया:

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

मुझे पता है कि वहाँ कुछ अंतर्निहित या मानक पुस्तकालय में होना चाहिए जो इसे और अधिक सरलता से करता है ...

यह हेक्स अंकों की एक स्ट्रिंग को परिवर्तित करने से अलग है जिसके लिए आप int (xxx, 16) का उपयोग कर सकते हैं, लेकिन इसके बजाय मैं वास्तविक बाइट मानों की एक स्ट्रिंग को परिवर्तित करना चाहता हूं।

अपडेट करें:

मुझे जेम्स की तरह का जवाब थोड़ा बेहतर लगता है क्योंकि इसे दूसरे मॉड्यूल को आयात करने की आवश्यकता नहीं होती है, लेकिन ग्रेग का तरीका तेज है:

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

कहने की जरूरत नहीं है, अगर आप इस पद्धति के बहुत सारे निष्पादन प्रति आयात कर रहे हैं, तो यह आनुपातिक रूप से एक समस्या से कम हो जाता है। यह शायद सीपीयू के बजाय i / o लागत है इसलिए यह विशेष मशीन की क्षमता और लोड विशेषताओं पर निर्भर हो सकता है।


और मानक lib से कुछ आयात करना बुरा है, क्यों?

एंडीवे, डुप्लिकेट: stackoverflow.com/questions/5415/…

26
आपका "आगे का अपडेट" अजीब है ... आप मॉड्यूल को इतनी बार क्यों आयात करेंगे?

5
मुझे पता है कि यह पुराना सवाल है। लेकिन अगर आप अन्य लोगों के लिए अपनी तुलना तारीख तक रखना चाहते हैं: मेरे कंप्यूटर पर मैकेनिकल घोंघे का जवाब ( int.from_bytes) आउट-प्रदर्शन किया struct.unpack। अधिक पठनीय इमो के आगे।
मग्गू_

जवाबों:


110

आप ऐसा करने के लिए संरचना मॉड्यूल का उपयोग भी कर सकते हैं :

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

3
चेतावनी: "एल" वास्तव में 8 बिट्स (4 नहीं) है 64 बिट पायथन बनाता है, इसलिए यह वहां विफल हो सकता है।
राफेल डोवगर्ड

12
राफेल: वास्तव में नहीं, चूंकि ग्रेग <का उपयोग कर रहा था, डॉक्स के अनुसार एल मानक आकार (4) "है, जब प्रारूप स्ट्रिंग '<', '>', 'में से एक से शुरू होता है!" या '=' docs.python.org/library/struct.html#format-characters
André Laszlo

59
यह उत्तर मनमाना-लंबाई बाइनरी स्ट्रिंग्स के लिए काम नहीं करता है।
amnnabb

4
प्रकार के विशिष्ट आकार होते हैं, यह कभी भी मनमाने ढंग से लम्बाई के बाइनरी स्ट्रिंग्स के लिए काम नहीं करेगा। यदि आप प्रत्येक आइटम के प्रकार को जानते हैं, तो आप इसे संभालने के लिए लूप सेट कर सकते हैं।
जोशुआ ओल्सन

2
"L" वास्तव में uint32 (4 बाइट्स) है। अगर मेरे मामले में आपको 8 बाइट्स की आवश्यकता है, तो "Q" -> uint64 का उपयोग करें। यह भी ध्यान दें कि "l" -> int32 और q -> int64
ntg

319

पायथन 3.2 में और बाद में, उपयोग करें

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

या

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

आपकी बाइट-स्ट्रिंग की समाप्ति के अनुसार ।

यह भी मनमाने ढंग से लंबाई के बाइटस्ट्रिंग-पूर्णांक के लिए काम करता है, और निर्दिष्ट करके दो-पूरक हस्ताक्षरित पूर्णांक के लिए signed=True। के लिए डॉक्सfrom_bytes देखें ।


@ मेरी कितनी धीमी है? जब मैं py3 में गया तो मैंने संरचना का उपयोग किया लेकिन int.from_bytes में परिवर्तित किया। मैं इस विधि को हर एमएस को कॉल कर रहा हूं क्योंकि मुझे सीरियल डेटा प्राप्त हो रहा है इसलिए किसी भी स्पीडअप का स्वागत है। मैं इसे देख रहा हूँ
नायब

@ निब, os.urandom(4)बाइट्स के लिए ** 1.4 structs ** (संरचना) बनाम ** 2.3 (s ** (int.from_bytes) मेरे सीपीयू पर। अजगर 3.5.2
एर

5
@ मैं ने सीआरसी विधियों के एक जोड़े का मूल्यांकन करने के लिए उपयोग की जाने वाली एक टाइम स्क्रिप्ट को फिर से जीवित किया। चार रन 1) संरचना 2) int.from_bytes 3) # 1 के रूप में लेकिन साइथन संकलित, 4) # 2 के रूप में लेकिन साइथन संकलित। संरचना के लिए 330ns, इंट के लिए 1.14us (साइथॉन ने शायद दोनों में 20ns स्पीडअप दिया ...) ऐसा लग रहा है कि मैं वापस स्विच कर रहा हूं :) यह समय से पहले अनुकूलन नहीं है, मैं कुछ बुरा बाधाओं को मार रहा हूं, विशेष रूप से पोस्ट करने के लिए एक मिलियन नमूनों के साथ। -प्रत्यक्ष और बंद भागों खटखटाया गया है।
नायब

66

जैसा कि ग्रेग ने कहा, यदि आप द्विआधारी मूल्यों के साथ काम कर रहे हैं, तो आप संरचना का उपयोग कर सकते हैं, लेकिन अगर आपके पास "हेक्स संख्या" है, लेकिन बाइट प्रारूप में आप इसे बस रूपांतरित करना चाहते हैं:

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

... यह इस प्रकार है:

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

... इसके अलावा यह बाइट्स की किसी भी संख्या के लिए काम करेगा।


3
वास्तव में "बाइनरी मान" और "हेक्स संख्या" के बीच अंतर क्या है, लेकिन बाइट प्रारूप में "???????"

"हेल्प स्ट्रक्चर" देखें। उदाहरण के लिए। "001122334455" .doscope ('हेक्स') को स्ट्रक्चर का उपयोग करके संख्या में परिवर्तित नहीं किया जा सकता है।
जेम्स एंटिल

3
वैसे, यह उत्तर मानता है कि पूर्णांक बड़े-एंडियन बाइट क्रम में एन्कोडेड है। छोटे-एंडियन ऑर्डर के लिए, करें:int(''.join(reversed(s)).encode('hex'), 16)
amcnabb

1
अच्छा है, लेकिन यह धीमा होने जा रहा है! लगता है कि अगर आप पायथन में कोडिंग कर रहे हैं तो वास्तव में कोई फर्क नहीं पड़ता।
मैटकॉशरन

8

मैं int, hex और बाइट्स के बीच डेटा परिवर्तित करने के लिए निम्न फ़ंक्शन का उपयोग करता हूं।

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" स्पेसियर और स्ट्रिंग की समाप्ति-> अंतर रूपांतरण दोनों आपके विशेष पायथन कार्यान्वयन पर निर्भर हैं। लेकिन यदि आप एक साथ कई पूर्णांक / स्ट्रिंग्स को परिवर्तित करना चाहते हैं, तो सरणी मॉड्यूल इसे जल्दी से करता है।


5

पायथन 2.x में, आप <Bअहस्ताक्षरित बाइट्स के लिए प्रारूप विनिर्देशक का उपयोग कर सकते हैं , और / के <bसाथ हस्ताक्षरित बाइट्स के लिए ।struct.unpackstruct.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: एक बाइट में भाग लें, 'ए' कहें:

>>> 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 के तहत काम करेगा। अंत में मैंने इसे लिखा, यह थोड़ा हैकी है क्योंकि यह एक स्ट्रिंग रूपांतरण करता है, लेकिन यह काम करता है।

पायथन 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

int.from_bytes सबसे अच्छा समाधान है अगर आप संस्करण> = 3.2 पर हैं। "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

हेक्स (बाइट्स 2िंट ([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

यह उस नकारात्मक संख्या के लिए काम नहीं करता है जिसे बाइट में परिवर्तित किया गया था।
मारिया

1

अजगर 3 में आप आसानी से बाइट स्ट्रिंग को पूर्णांकों (0..255) की सूची में बदल सकते हैं

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

0

एक शालीन तरीके से एरे का उपयोग करने की त्वरित विधि। कुछ समय से मैं इसका उपयोग कर रहा हूं:

पूर्वनिर्धारित चर:

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

यह संभव है कि ये अधिक तेज़ हो सकते हैं।

संपादित करें:
कुछ नंबरों के लिए, यहां एक प्रदर्शन परीक्षण (एनाकोंडा 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%

यह एक कच्चा प्रदर्शन परीक्षण है, इसलिए एंडियन पॉव-फ्लिप को छोड़ दिया गया है। पता चला समारोह पाश के लिए के रूप में ही पारी-oring आपरेशन लागू होती है और सिर्फ है उसके बगल में सबसे तेजी से पुनरावृत्ति प्रदर्शन के रूप में ।
shiftarrarray.array('B',[0,0,255,0])dict

मुझे संभवतः यह भी ध्यान देना चाहिए कि दक्षता को औसत समय तक सटीकता से मापा जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.