4
\$\begingroup\$

In order to save memory space. Strings inside an embedded device are stored in a particular way. Each 32-bit location holds up to 4 chars instead of only 1 char in the usual case.

I wrote a function that convert an encoded string back to its original string. I am new to Python, so I would like to know whether or not I can simplify my code.

The string is encoded in such way that I need to reverse the order of each group of 4 chars.

#!/usr/bin/python
def arrayOfInt2string(array):
    s = ''
    for a in array:
        a = "%0.8x" % a
        b = list()
        for i in range(0, len(a), 2):
            b.append(chr(int(a[i:i+2], 16)))            
        s = s + ''.join(b.reverse())
    return s

r = (
    0x33323130,
    0x37363534,
    0x00000038,
    0x00000000
)
arrayOfInt2string(r)   

The output is:

"012345678"
\$\endgroup\$
5
\$\begingroup\$

If you are going to be playing with string representations of native types, you probably want to take a look at the struct standard library package.

With it, you can quickly process your r as follows:

>>> import struct
>>> ''.join(struct.pack('i', rr) for rr in r)
'012345678\x00\x00\x00\x00\x00\x00\x00'

And you can play with the ordering of the characters by explicitly describing the endianess of your input:

>>> ''.join(struct.pack('>i', rr) for rr in r)  # big endian
'32107654\x00\x00\x008\x00\x00\x00\x00'
\$\endgroup\$
4
\$\begingroup\$

First, your function name could use a more clear name. arrayOfInt2string contains a lot of information but none of it makes it clear what the user of function actually is. decode_str is more clear. Likewise, array is a bad parameter. The data you're passing is a tuple, not an array. But regardless the type is not a good indicator of what it is. encoded_str would be clearer. As much as possible, come up with relevant names to make your script easier to read.

You can initialise b just using b = []. But even better would be to use a list comprehension. A list comprehension collapses a for loop into a single line expression to generate a list. In your case, you can create your whole b list in just one line like this:

        b = [chr(int(a[i:i+2], 16)) for i in range(0, len(a), 2)]

It basically flips the syntax of your for loop around. You have your expression for each element of b followed by the syntax of your for loop. If you really wanted to, both for loops could be collapsed this way, but that would probably read as too complicated to follow.

For your s assignment, you can use the += operator. It basically says to add whatever is on the right of the operator to the current value of s. It's shorthand to essentially do what your code already does.

        s += ''.join(b.reverse())

Using ''.join(b.reverse()) is not strictly necessary. You can use the slicing operator to reverse it in a shorter line. You've used the slicing operator elsewhere, but you may or may not be aware of the third parameter it takes called the step parameter. It basically tells Python what amount to increment each step by, similar to the third parameter you pass to range. You can pass a negative value to start at the end and go backwards, so you can flip b like this: b[::-1].

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.