9
\$\begingroup\$

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?

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Oct 22, 2014 at 22:34
\$\endgroup\$
1
  • \$\begingroup\$ e.g. "0x" + ("0"*8 + s[2:])[-8:] \$\endgroup\$ Commented Sep 27, 2021 at 13:46

3 Answers 3

14
\$\begingroup\$

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')
answered Oct 22, 2014 at 22:42
\$\endgroup\$
0
6
\$\begingroup\$

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.

answered Oct 22, 2014 at 23:14
\$\endgroup\$
1
\$\begingroup\$

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)
answered Oct 23, 2014 at 12:14
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.