For solving the left-side trailing zero problem:
my_hexdata = "1a"
scale = 16 ## equals to hexadecimal
num_of_bits = 8
bin(int(my_hexdata, scale))[2:].zfill(num_of_bits)
It will give 00011010 instead of the trimmed version.
Answer from Onedinkenedi on Stack OverflowFor solving the left-side trailing zero problem:
my_hexdata = "1a"
scale = 16 ## equals to hexadecimal
num_of_bits = 8
bin(int(my_hexdata, scale))[2:].zfill(num_of_bits)
It will give 00011010 instead of the trimmed version.
Convert hex to binary
I have ABC123EFFF.
I want to have 001010101111000001001000111110111111111111 (i.e. binary repr. with, say, 42 digits and leading zeroes).
Short answer:
The new f-strings in Python 3.6 allow you to do this using very terse syntax:
>>> f'{0xABC123EFFF:0>42b}'
'001010101111000001001000111110111111111111'
or to break that up with the semantics:
>>> number, pad, rjust, size, kind = 0xABC123EFFF, '0', '>', 42, 'b'
>>> f'{number:{pad}{rjust}{size}{kind}}'
'001010101111000001001000111110111111111111'
Long answer:
What you are actually saying is that you have a value in a hexadecimal representation, and you want to represent an equivalent value in binary.
The value of equivalence is an integer. But you may begin with a string, and to view in binary, you must end with a string.
Convert hex to binary, 42 digits and leading zeros?
We have several direct ways to accomplish this goal, without hacks using slices.
First, before we can do any binary manipulation at all, convert to int (I presume this is in a string format, not as a literal):
>>> integer = int('ABC123EFFF', 16)
>>> integer
737679765503
alternatively we could use an integer literal as expressed in hexadecimal form:
>>> integer = 0xABC123EFFF
>>> integer
737679765503
Now we need to express our integer in a binary representation.
Use the builtin function, format
Then pass to format:
>>> format(integer, '0>42b')
'001010101111000001001000111110111111111111'
This uses the formatting specification's mini-language.
To break that down, here's the grammar form of it:
[[fill]align][sign][#][0][width][,][.precision][type]
To make that into a specification for our needs, we just exclude the things we don't need:
>>> spec = '{fill}{align}{width}{type}'.format(fill='0', align='>', width=42, type='b')
>>> spec
'0>42b'
and just pass that to format
>>> bin_representation = format(integer, spec)
>>> bin_representation
'001010101111000001001000111110111111111111'
>>> print(bin_representation)
001010101111000001001000111110111111111111
String Formatting (Templating) with str.format
We can use that in a string using str.format method:
>>> 'here is the binary form: {0:{spec}}'.format(integer, spec=spec)
'here is the binary form: 001010101111000001001000111110111111111111'
Or just put the spec directly in the original string:
>>> 'here is the binary form: {0:0>42b}'.format(integer)
'here is the binary form: 001010101111000001001000111110111111111111'
String Formatting with the new f-strings
Let's demonstrate the new f-strings. They use the same mini-language formatting rules:
>>> integer = 0xABC123EFFF
>>> length = 42
>>> f'{integer:0>{length}b}'
'001010101111000001001000111110111111111111'
Now let's put this functionality into a function to encourage reusability:
def bin_format(integer, length):
return f'{integer:0>{length}b}'
And now:
>>> bin_format(0xABC123EFFF, 42)
'001010101111000001001000111110111111111111'
Aside
If you actually just wanted to encode the data as a string of bytes in memory or on disk, you can use the int.to_bytes method, which is only available in Python 3:
>>> help(int.to_bytes)
to_bytes(...)
int.to_bytes(length, byteorder, *, signed=False) -> bytes
...
And since 42 bits divided by 8 bits per byte equals 6 bytes:
>>> integer.to_bytes(6, 'big')
b'\x00\xab\xc1#\xef\xff'
python - Converting hex to binary in the form of string - Code Review Stack Exchange
Python conversion from binary string to hexadecimal - Stack Overflow
Write a hex string as binary data in Python - Stack Overflow
python convert hex string to formated binary string - Stack Overflow
Review
You don't have a lot of code here to review, so this will necessarily be short.
- PEP-8: The Style Guide for Python Code recommends:
snake_casefor functions, variables, and parameters. SoaStringshould bea_string, andretValshould beret_val.
- Better parameter names
- What is
aString?"Hello World"is a string, but we can't use it, because you are actually expecting a hexadecimal string. Perhapshex_stringwould be a better parameter name. - Similarly,
binary_stringwould be more descriptive thanretStr.
- What is
- A
'''docstring'''would be useful for the function. - Type hints would also be useful.
Alternate Implementation
Doing things character-by-character is inefficient. It is usually much faster to let Python do the work itself with its efficient, optimized, native code functions.
Python strings formatting supports adding a comma separator between thousand groups.
>>> f"{123456789:,d}"
'123,456,789'
It also supports adding underscores between groups of 4 digits when using the binary or hexadecimal format codes:
>>> f"{548151468:_x}"
'20ac_20ac'
>>> f"{0x20AC:_b}"
'10_0000_1010_1100'
That is most of the way to what you're looking for. Just need to turn underscores to spaces, with .replace(...) and fill with leading zeros by adding the width and 0-fill flag to the format string.
>>> f"{0x20AC:019_b}".replace('_', ' ')
'0010 0000 1010 1100'
A function using this technique could look like:
def str_bin_in_4digits(hex_string: str) -> str:
"""
Turn a hex string into a binary string.
In the output string, binary digits are space separated in groups of 4.
>>> str_bin_in_4digits('20AC')
'0010 0000 1010 1100'
"""
value = int(hex_string, 16)
width = len(hex_string) * 5 - 1
bin_string = f"{value:0{width}_b}"
return bin_string.replace('_', ' ')
if __name__ == '__main__':
import doctest
doctest.testmod(verbose=True)
Depending on your definition of elegant, you can one-line this:
def str_bin_in_4digits(hex_string: str) -> str:
"""
Turn a hex string into a binary string.
In the output string, binary digits are space separated in groups of 4.
>>> str_bin_in_4digits('20AC')
'0010 0000 1010 1100'
"""
return f"{int(hex_string,16):0{len(hex_string)*5-1}_b}".replace('_', ' ')
The problem is to take a hex string and convert it to the equivalent binary string. Each character in the input string maps to a one or more characters in the output string, e.g., '0' -> '0000', ... 'A' -> '1010', ... 'F' -> '1111'. This is a perfect fit for string.translate()
table = ''.maketrans({'0':'0000 ', '1':'0001 ', '2':'0010 ', '3':'0011 ',
'4':'0100 ', '5':'0101 ', '6':'0110 ', '7':'0111 ',
'8':'1000 ', '9':'1001 ', 'A':'1010 ', 'B':'1011 ',
'C':'1100 ', 'D':'1101 ', 'E':'1110 ', 'F':'1111 '})
def str_bin_in_4digits(hex_string):
return hex_string.upper().translate(table)
It's 6-7 times faster.
int given base 2 and then hex:
>>> int('010110', 2)
22
>>> hex(int('010110', 2))
'0x16'
>>>
>>> hex(int('0000010010001101', 2))
'0x48d'
The doc of int:
int(x[, base]) -> integer Convert a string or number to an integer, if possible. A floatingpoint argument will be truncated towards zero (this does not include a string representation of a floating point number!) When converting a string, use the optional base. It is an error to supply a base when converting a non-string. If base is zero, the proper base is guessed based on the string content. If the argument is outside the integer range a long object will be returned instead.
The doc of hex:
hex(number) -> string Return the hexadecimal representation of an integer or longinteger.
bstr = '0000 0100 1000 1101'.replace(' ', '')
hstr = '%0*X' % ((len(bstr) + 3) // 4, int(bstr, 2))
You're looking for binascii.
binascii.unhexlify(hexstr)
Return the binary data represented by the hexadecimal string hexstr.
This function is the inverse of b2a_hex(). hexstr must contain
an even number of hexadecimal digits (which can be upper or lower
case), otherwise a TypeError is raised.
import binascii
hexstr = 'FF0000FF'
binstr = binascii.unhexlify(hexstr)
You could use bytes's hex and fromhex like this:
>>> ss = '7e7e303035f8350d013d0a'
>>> bytes.fromhex(ss)
b'~~005\xf85\r\x01=\n'
>>> bb = bytes.fromhex(ss)
>>> bytes.hex(bb)
'7e7e303035f8350d013d0a'
hex maps one digit to one nibble ... so you can do it quite easily with a lookup table
hex2bin_map = {
"0":"0000",
"1":"0001",
"2":"0010",
"3":"0011",
"4":"0100",
"5":"0101",
"6":"0110",
"7":"0111",
"8":"1000",
"9":"1001",
"A":"1010",
"B":"1011",
"C":"1100",
"D":"1101",
"E":"1110",
"F":"1111",
}
hex_num="1234"
print "_".join(hex2bin_map[i] for i in hex_num)
# 0001_0010_0011_0100
this isnt as terse as the other answer(s) im sure ... but its probably the most performant ... and its pretty dang easy to read (ie you dont need to worry about the grouper pattern of zip, nor regex's, which are bound to confuse newer programmers)
As an alternative to generic sequence chunking, for strings, you can use a regex to group and replace:
>>> '0b' + re.sub(r'(\d{4})(?!$)', r'\1_', format(int('0x1234', 16), '016b'))
'0b0001_0010_0011_0100'
In Python 3.6, you will be able to do this with a format specifier (see PEP 515)
'0b' + format(int('0x1234', 16), '016_b')
or, if you prefer:
'0b{:016_b}'.format(int('0x1234', 16))
You can use ord and hex like this :
>>> s = 'some string'
>>> hex_chars = map(hex,map(ord,s))
>>> print hex_chars
['0x73', '0x6f', '0x6d', '0x65', '0x20', '0x73', '0x74', '0x72', '0x69', '0x6e', '0x67']
>>> hex_string = "".join(c[2:4] for c in hex_chars)
>>> print hex_string
736f6d6520737472696e67
>>>
Or use the builtin encoding :
>>> s = 'some string'
>>> print s.encode('hex_codec')
736f6d6520737472696e67
>>>
>>> import binascii
>>> s = '2F'
>>> hex_str = binascii.b2a_hex(s)
>>> hex_str
>>> '3246'
OR
>>>import binascii
>>> hex_str = binascii.hexlify(s)
>>> hex_str
>>> '3246'
>>>