Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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?

share|improve this question

3 Answers 3

up vote 2 down vote accepted

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')
share|improve this answer
    
This is exactly what I was looking for. Thanks! –  Sohcahtoa82 Oct 23 '14 at 17:42

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)
share|improve this answer
    
This solution is even more verbose than my original solution and ignores the fact that I already said that my input is always a string. You've turned a single line of code into a 13-line function. You'd fit right in as an enterprise programmer! –  Sohcahtoa82 Oct 23 '14 at 17:40

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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