I'm given a hexadecimal number in string form with a leading "0x"
that may contain 1-8 digits, but I need to pad the number with zeros so that it always has 8 digits (10 characters including the "0x"
).
For example:
"0x123"
should become"0x00000123"
."0xABCD12"
should become"0x00ABCD12"
."0x12345678"
should be unchanged.
I am guaranteed to never see more than 8 digits, so this case does not need to be handled.
Right now, I have this coded as:
padded = '0x' + '0' * (10 - len(mystring)) + mystring[2:]
It works, but feels ugly and unpythonic. Any suggestions for a cleaner method?
3 Answers 3
Perhaps you're looking for the .zfill
method on strings. From the docs:
Help on built-in function zfill: zfill(...) S.zfill(width) -> string Pad a numeric string S with zeros on the left, to fill a field of the specified width. The string S is never truncated.
Your code can be written as:
def padhexa(s):
return '0x' + s[2:].zfill(8)
assert '0x00000123' == padhexa('0x123')
assert '0x00ABCD12' == padhexa('0xABCD12')
assert '0x12345678' == padhexa('0x12345678')
I would suggest interpreting the input as a number, then using standard number-formatting routines.
padded = str.format('0x{:08X}', int(mystring, 16))
The string → int → string round trip may seem silly, but it is also beneficial in that it provides validation of the input string.
I'd use something like this:
def format_word(word, prefix=None, size=None):
if prefix is None:
prefix = '0x'
if size is None:
size = 2
if not isinstance(word, int):
word = int(word, 16)
if word > 2**(8 * size) - 1:
raise ValueError('word too great')
return '{prefix}{word:0{padding}X}'.format(
prefix=prefix,
word=word,
padding=2 * size)
Using None
as defaults and assigning true defaults later makes it easier to wrap the function.
def format_word(word, prefix=None, size=None):
if prefix is None:
prefix = '0x'
if size is None:
size = 2
If word
isn't already a int
try to convert it. It'll choke if it's not a str
, bytes
, or bytearray
. We need the type check because int(word, 16)
would choke if word
was already an `int.
if not isinstance(word, int):
word = int(word, 16)
Check that the word
isn't going break the formatting.
if word > 2**(8 * size) - 1:
raise ValueError('word too great')
Finally, format the word, using keywords to decouple the string to the argument order.
return '{prefix}{word:0{padding}X}'.format(
prefix=prefix,
word=word,
padding=2 * size)
"0x" + ("0"*8 + s[2:])[-8:]
\$\endgroup\$