Python hexidecimal address packing from string - python

This works correctly:
packed = struct.pack('<L',0x7c023a4f)
This does not:
address = '0x7c023a4f'
packed = struct.pack('<L',address)
How do i make this work?
I tried a lot of methods from the binascii library but i cannot seem to figure it out.

You can use literal_eval to evaluate the string as hex number before packing it:
from ast import literal_eval
address = '0x7c023a4f'
packed = struct.pack('<L', literal_eval(address))
packed
# 'O:\x02|'

Convert it to an integer:
address = '0x7c023a4f'
packed = struct.pack('<L', int(address, 16))

Related

How to convert independent bytes to bytearray?

Iam receiving single bytes via serial and I know, that every 4 of them are a float. F.e. I receive b'\x3c' and b'\xff' and I want it to be b'\x3c\xff'.
What is the best way to convert it?
You can use join() as you do with strings.
byte_1 = b'\x3c'
byte_2 = b'\xff'
joined_bytes = b''.join([byte_1, byte_2]) #b'\x3c\xff'
You can use it along the struct module to obtain your decoded float, be aware it returns a tuple even if it has only one element inside.
import struct
byte_1 = b'\x3c'
byte_2 = b'\xff'
byte_3 = b'\x20'
byte_4 = b'\xff'
joined_bytes = b''.join([byte_1, byte_2, byte_3, byte_4])
result = struct.unpack('f', joined_bytes)
print(result[0])

Converting string with leading-zero integer to json

I convert a string to a json-object using the json-library:
a = '{"index":1}'
import json
json.loads(a)
{'index': 1}
However, if I instead change the string a to contain a leading 0, then it breaks down:
a = '{"index":01}'
import json
json.loads(a)
>>> JSONDecodeError: Expecting ',' delimiter
I believe this is due to the fact that it is invalid JSON if an integer begins with a leading zero as described in this thread.
Is there a way to remedy this? If not, then I guess the best way is to remove any leading zeroes by a regex from the string first, then convert to json?
A leading 0 in a number literal in JSON is invalid unless the number literal is only the character 0 or starts with 0.. The Python json module is quite strict in that it will not accept such number literals. In part because a leading 0 is sometimes used to denote octal notation rather than decimal notation. Deserialising such numbers could lead to unintended programming errors. That is, should 010 be parsed as the number 8 (in octal notation) or as 10 (in decimal notation).
You can create a decoder that will do what you want, but you will need to heavily hack the json module or rewrite much of its internals. Either way, you will see a performance slow down as you will no longer be using the C implementation of the module.
Below is an implementation that can decode JSON which contains numbers with any number of leading zeros.
import json
import re
import threading
# a more lenient number regex (modified from json.scanner.NUMBER_RE)
NUMBER_RE = re.compile(
r'(-?(?:\d*))(\.\d+)?([eE][-+]?\d+)?',
(re.VERBOSE | re.MULTILINE | re.DOTALL))
# we are going to be messing with the internals of `json.scanner`. As such we
# want to return it to its initial state when we're done with it, but we need to
# do so in a thread safe way.
_LOCK = threading.Lock()
def thread_safe_py_make_scanner(context, *, number_re=json.scanner.NUMBER_RE):
with _LOCK:
original_number_re = json.scanner.NUMBER_RE
try:
json.scanner.NUMBER_RE = number_re
return json.scanner._original_py_make_scanner(context)
finally:
json.scanner.NUMBER_RE = original_number_re
json.scanner._original_py_make_scanner = json.scanner.py_make_scanner
json.scanner.py_make_scanner = thread_safe_py_make_scanner
class MyJsonDecoder(json.JSONDecoder):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# overwrite the stricter scan_once implementation
self.scan_once = json.scanner.py_make_scanner(self, number_re=NUMBER_RE)
d = MyJsonDecoder()
n = d.decode('010')
assert n == 10
json.loads('010') # check the normal route still raise an error
I would stress that you shouldn't rely on this as a proper solution. Rather, it's a quick hack to help you decode malformed JSON that is nearly, but not quite valid. It's useful if recreating the JSON in a valid form is not possible for some reason.
First, using regex on JSON is evil, almost as bad as killing a kitten.
If you want to represent 01 as a valid JSON value, then consider using this structure:
a = '{"index" : "01"}'
import json
json.loads(a)
If you need the string literal 01 to behave like a number, then consider just casting it to an integer in your Python script.
How to convert string int JSON into real int with json.loads
Please see the post above
You need to use your own version of Decoder.
More information can be found here , in the github
https://github.com/simplejson/simplejson/blob/master/index.rst
c = '{"value": 02}'
value= json.loads(json.dumps(c))
print(value)
This seems to work .. It is strange
> >>> c = '{"value": 02}'
> >>> import json
> >>> value= json.loads(json.dumps(c))
> >>> print(value) {"value": 02}
> >>> c = '{"value": 0002}'
> >>> value= json.loads(json.dumps(c))
> >>> print(value) {"value": 0002}
As #Dunes, pointed out the loads produces string as an outcome which is not a valid solution.
However,
DEMJSON seems to decode it properly.
https://pypi.org/project/demjson/ -- alternative way
>>> c = '{"value": 02}'
>>> import demjson
>>> demjson.decode(c)
{'value': 2}

Not able to convert to string

I might be using wrong python terminology.
I have an array of 3 integer elements: month, date and year.
However, I am not able to print each individual element when concatenating strings.
import ssl
import OpenSSL
import time
import sys
def get_SSL_Expiry_Date(host, port):
cert = ssl.get_server_certificate((host, 443))
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
raw_date = x509.get_notAfter()
decoded_date = raw_date.decode("utf-8")
dexpires = time.strptime(decoded_date, "%Y%m%d%H%M%Sz")
bes = dexpires.tm_mon,dexpires.tm_mday,dexpires.tm_year
print (bes)
#print(bes[0]+"/"+bes[1]+"/"+bes[2])
domain = sys.argv[1]
port = 443
get_SSL_Expiry_Date(domain, port)
If I uncomment line 14, I get an error:
TypeError: unsupported operand type(s) for +: 'int' and 'str'
I am trying to get the date in this format (all strings): Month/Date/Year.
What am I doing wrong?
You can use Python's format() method to handle it (much cleaner also):
print("{0}/{1}/{2}".format(bes[0],bes[1],bes[2]))
...or further simplified (thanks Anton)
print("{0}/{1}/{2}".format(*bes))
↳ Python String Formatting
Simply use:
print(time.strftime("%m/%d/%y",dexpires))
See also https://docs.python.org/3/library/time.html
In general python modules usually contain all kinds of reformatting functions you don't have to reinvent them.
Example:
>>> dexpires=time.strptime('20180823131455z','%Y%m%d%H%M%Sz')
>>> dexpires
time.struct_time(tm_year=2018, tm_mon=8, tm_mday=23, tm_hour=13, tm_min=14, tm_sec=55, tm_wday=3, tm_yday=235, tm_isdst=-1)
>>> time.strftime('%m/%d/%y',dexpires)
'08/23/18'
>>>
First you have to convert int values to string than only you are able to concave them.
You can use str() inbuilt method
print(str(bes[0])+"/"+ str(bes[1])+"/"+ str(bes[2])) #convert int to str first.

extract list or tuple inside string

I am getting input from an external device connected via Ethernet, and it is passing several values of string type e.g. value = '(2,2)\n'. I would like to assign these values to a list or tuple variable e.g. final_value = (2,2).
The code I am using is the following:
import socket
sock = socket.socket()
value =sock.recv(buffersize=2048)
formatted_value = eval(value)
I read that the eval function I am using at this moment to get the list is not a very safe approach, as the external device could pass a dangerous script. So, I would like to know if there is any alternative, similar to the function int(), which can be used to get an integer from a string.
Use ast module literal_eval method for a safer eval
import ast
formatted_value = ast.literal_eval(value)
If you know the input contains a tuple
from ast import literal_eval as make_tuple
make_tuple(value)
Well to give the alternative approach you can do.
s = '(2, 2)\n'
s = s.strip()
if s.startswith('(') and s.endswith(')'):
tup = tuple(int(i) for i in s[1:-1].split(','))
print(tup)
Or if you want a list
s = '(2, 2)\n'
s = s.strip()
if s.startswith('(') and s.endswith(')'):
lst = [int(i) for i in s[1:-1].split(',')]
print(lst)

Unable convert to int from bytes

I have the next value
value = bytearray(b'\x85\x13\xbd|\xfb\xbc\xc3\x95\xbeL6L\xfa\xbf0U_`$]\xca\xee]z\xef\xa0\xd6(\x15\x8b\xca\x0e\x1f7\xa9\xf0\xa4\x98\xc5\xdf\xcdM5\xef\xc2\x052`\xeb\x13\xd9\x99B.\x95\xb2\xbd\x96\xd9\x14\xe6F\x9e\xfd\xd8\x00')
when I try to convert in python3.x it works well.
>>> int.from_bytes(value, byteorder='little')
2909369579440607969688280064437289348250138784421305732473112318543540722321676649649580720015118044118243611774710427666475769804427735898727217762490192773
How to convert it in python2.7? I already read the convert a string of bytes into an int (python)
struct.unpack(fmt, value)[0]
But don't know what to do with fmt.
You can just write your own from_bytes function in Python 2:
def from_bytes (data, big_endian = False):
if isinstance(data, str):
data = bytearray(data)
if big_endian:
data = reversed(data)
num = 0
for offset, byte in enumerate(data):
num += byte << (offset * 8)
return num
Used like this:
>>> data = b'\x85\x13\xbd|\xfb\xbc\xc3\x95\xbeL6L\xfa\xbf0U_`$]\xca\xee]z\xef\xa0\xd6(\x15\x8b\xca\x0e\x1f7\xa9\xf0\xa4\x98\xc5\xdf\xcdM5\xef\xc2\x052`\xeb\x13\xd9\x99B.\x95\xb2\xbd\x96\xd9\x14\xe6F\x9e\xfd\xd8\x00'
>>> from_bytes(data)
2909369579440607969688280064437289348250138784421305732473112318543540722321676649649580720015118044118243611774710427666475769804427735898727217762490192773L
As for struct, you cannot really use this, as it only supports unpacking elements of a certain kind, up to 8 byte integers. But since you want to handle arbitrary byte strings, you will have to use something else.
You can use a combination of .encode('hex') and int(x, 16):
num = int(str(value).encode('hex'), 16)
Note that you need to use something like
int(''.join(reversed(value)).encode('hex'), 16)
in order to parse it as little endian.
reference: https://stackoverflow.com/a/444814/8747

Categories

Resources