Month: April 2016

Reading numbers

Often there is a difference in the way your program needs to use a number and the way someone using the program would want to enter it. A good example is file size. Your program is probably going to want to know the number of bytes but person using your program is going to want to be something a lot more flexible, like the ability to specify the size in Mb. And not just the as a whole megabyte either, how about allowing 0.5M.

Thankfully this flexibility can be achieved without too much work. First of all we need a reliable way of converting a string into a number. Ideally this should be smart about it so that if you enter 3 you get an integer and if you enter 2.5 you get a floating point number back. Add in the ability to specify a default value and to turn off floating point numbers and you end with the the following fairly self explanatory function.

def tonum(string, default=0, allow_float=True):
    num = default
    try:
        num = int(string)
    except ValueError:
        if allow_float:
            try:
                num = float(string)
            except ValueError:
                pass
    return num

Now to put this to good use. The first thing to you need to know is if a valid letter has been included. If so convert the number part and then multiply it by the whatever the letter stands for. Finally make sure the result is an integer (you cannot have fractions of a byte). If there is no letter then just convert to an integer. This can either be done by setting allow_float=False in the call to tonum if you want only strict integers or converting like I have done if you want to allow some more exotic ways of specifying numbers.

# assume the string to convert is in the variable sizestr
multiplier = { 'k': 1024, 'm': 1024*1024, 'g': 1024*1024*1024, 't': 1024*1024*1024*1024 }
if sizestr[-1] in ('k','K','m','M','g','G','t','T'):
    numbytes = int(tonum(sizestr[:-1])*multiplier[sizestr[-1].lower()])
else:
    numbytes = int(tonum(size))

These 16 lines of codes handle some really strange looking examples like 1e3k for 100Kb (1024000 bytes). The code naturally lends itself handling arguments passed in to program (from getopts or similar), from a GUI or read in from a file.

Hopefully this will give you a start if you need to handle something similar.