David542
David542

Reputation: 110093

Given a string representing a real number in decimal, how can I count the number of needed (non-zero) decimal places?

How would I do the following:

>>> num_decimal_places('3.2220')
3 # exclude zero-padding

>>> num_decimal_places('3.1')
1

>>> num_decimal_places('4')
0

I was thinking of doing:

len((str(number) if '.' in str(number) else str(number) + '.').rstrip('0').split('.')[-1])

Is there another, simpler way to do this?

Upvotes: 6

Views: 3076

Answers (9)

Karl Knechtel
Karl Knechtel

Reputation: 61498

Use the partition method of strings to get the decimal portion - this returns a 3-tuple regardless of whether the string actually contains a decimal point or any digits after it. Then simply remove trailing zeros from the decimal portion and count the remaining digits. Thus:

def needed_precision(number_string):
    whole, period, decimal = number_string.partition('.')
    return len(decimal.rstrip('0'))

This can of course be inlined:

len(number_string.partition('.')[2].rstrip('0'))

Which is less readable, but quite short and straightforward.

Upvotes: 0

Feuermurmel
Feuermurmel

Reputation: 9922

The Decimal type is perfect for this, you can implement num_decimal_places() as follows:

from decimal import Decimal

def num_decimal_places(value: str):
    return -Decimal(value).normalize().as_tuple().exponent

It works as follows: Decimal(value) parses the string, including exponent notation, then .normalize() strips any trailing zeros from the internal representation. .as_tuple().exponent contains the number of decimal places the internally stored integer is shifted to the left, so negative numbers specify the number of places to the right of the decimal.

Upvotes: 0

Moinuddin Quadri
Moinuddin Quadri

Reputation: 48067

The best and the most Pythonic way to achieve this is:

import decimal
x = '56.001000'
x = x.rstrip('0')  # returns '56.001'
x = decimal.Decimal(x)  # returns Decimal('0.001')
x = x.as_tuple().exponent  # returns -3
x = abs(x)  #returns 3

Above code can be written in simpler way as:

>>> x = '56.001000'
>>> abs(decimal.Decimal(x.rstrip('0')).as_tuple().exponent)
3

Below is the list of used functions for more reference:

  1. str.rstrip(): Return a copy of the string with trailing characters removed.
  2. decimal.Decimal(): Construct a new Decimal object based from value.
  3. x.as_tuple(): Returns a namedtuple of the format: DecimalTuple(sign=0, digits=(1,), exponent=-3)
  4. abs(): Return the absolute value of a number.

Upvotes: 3

Kasravnd
Kasravnd

Reputation: 107287

You dont need regex, you can convert to float and convert back to string! this automatically will remove the zeroes :

>>> def convertor(s):
...       try :
...          int(s.rstrip('0').rstrip('.'))
...          return 0
...       except: 
...          return len(str(float(s)).split('.')[-1])
... 
>>> convertor('4.0230')
3
>>> convertor('4.0')
0
>>> convertor('4')
0

Upvotes: 2

ferhatelmas
ferhatelmas

Reputation: 3978

import re

def f(s):
    ls = s.split('.', 1)
    if len(ls) == 2 and re.match(r'\d*$', ls[1]):
        return len(ls[1].rstrip('0'))
    return 0

assert f('12') == 0
assert f('12.') == 0
assert f('12.1') == 1
assert f('12.100006') == 6
assert f('12.1.3') == 0
assert f('12.1abc') == 0
assert f('12.100000') == 1

Upvotes: 0

acushner
acushner

Reputation: 9946

you could also just try something like:

try:
    return len(str(num).split('.')[1].rstrip('0'))
except
    return 0

Upvotes: 1

Vivek Sable
Vivek Sable

Reputation: 10213

By string process:

  1. Check . is present in number string or not.
  2. If Not present then return 0.
  3. If present the split number string by . and get second item from the split result.
  4. Remove 0 from the right side.
  5. Return len of item.

code:

>>> def dCount(no_str):
...    if "." in no_str:
...         return len(no_str.split(".")[1].rstrip("0"))
...    else:
...         return 0
... 
>>> dCount("2")
0
>>> dCount("2.002")
3
>>> dCount("2.1230")
3
>>> dCount("2.01230")
4
>>> 

Upvotes: 1

Stefano Sanfilippo
Stefano Sanfilippo

Reputation: 33046

You can use a regex to parse value, capture the decimal digits and count the length of the match, if any:

import re

def num_decimal_places(value):
    m = re.match(r"^[0-9]*\.([1-9]([0-9]*[1-9])?)0*$", value)
    return len(m.group(1)) if m is not None else 0

this is a bit less "raw" than splitting the string with multiple if else, not sure if simpler or more readable, though.

Upvotes: 4

Pedro Braz
Pedro Braz

Reputation: 2401

You could try using the Decimal function in python:

abs(Decimal(string_value).as_tuple().exponent)

as explained in Easy way of finding decimal places

Upvotes: -1

Related Questions