# Character to decimal conversion

Posted on

Problem

This converts from character representation of integers to their decimal value:

``````def chrtodec(str):
dec = 0
base = ord('0')
for chr in str:
dec = dec * 10 + ord(chr) - base
return dec
``````

For example: “123” -> 123

Solution

You shouldn’t use `chr` or `str` as names because they shadow the builtin `chr` and `str` methods. If you then wanted to use `str()` you’d be out of luck because `str` is now a string instead of a function. Given that your function deals with both strings and character ordinals it is not unlikely that these could be used. `string` is a potential improvement, it can occasionally cause trouble if you’re trying to use the `string` module of the same name.

``````def chrtodec(str):
"""Converts a string to a float using character ordinal positions."""
``````

I think you have another big problem though, which is invalid input handling. Take a look at these:

``````>>> chrtodec("hello")
619663
>>> chrtodec("12.21")
11821
>>> chrtodec("523.32f")
5228374
``````

Clearly there are problems here when you have characters other than numbers, so I think what you should do is raise a `ValueError` when an invalid string is passed. You already have the tools to do this figured out of course if you just check that a character’s ordinal fits in the right range.

``````if not (ord('0') <= ord(chr) <= ord('9')):
raise ValueError("Invalid character {} in string {},"
"only digits are parseable.".format(chr, str))
``````

You could also just use `chr.isdigit()` as @Barry pointed out.

Also you could add support for negative numbers by checking at the start if the first character is `ord('-')`.

``````negative = ord(str[0]) == ord('-')
``````

This evaluates the expression `str[0] == ord('-')` and sets `negative` as the boolean result. Note that to make this compatible with the error handling I suggested, you should then remove the first character from `str`. And probably update the error message and docstring too.

``````if negative:
str = str[1:]
``````

Then just return with a ternary that checks `negative`.

``````return dec if not negative else -dec
``````

Your code lacks modularization, This problem can be decomposed in:

• Find the numerical value of a char.
• Transform the chars into digits
• Multiply all this numerical values by 10 ** position and sum them.
``````def char_to_integer(char):
return ord(char) - ord('0')
``````

The second function is an excellent place for a generator expression:

``````def string_to_digits(string):
return (char_to_integer(i) for i in string)
``````

Finally:

``````def digits_to_integer(digits):
return sum(digit * 10 ** ( len(digits) - position )
for position, digit in enumerate(digits))
``````

You don’t support negative numbers. But that’s actually pretty easy to add, all you need to do is:

``````chrtodec = int
``````

That also has the handy ability to support arbitrary base conversions too!

I’ve come to love the “straight-to-the-point” Python syntax a lot, and I embrace the delicious syntactic sugar of the language; but I keep seeing really bad naming of things among Python programmers. Maybe try this?

``````def number_as_string_to_decimal(number_as_string):
decimal = 0
base = ord('0')
for character in number_as_string:
decimal = decimal * 10 + ord(character) - base
return decimal
``````