A Python module 'isnumeric'

vegaseat 1 Tallied Votes 2K Views Share

A simple test of a numeric string.

''' isnumeric.py
test a numeric string s if it's usable for int(s) or float(s)
'''

def isnumeric(s):
    '''returns True if string s is numeric'''
    return all(c in "0123456789.+-" for c in s)

# test module ...
if __name__ == '__main__':
    print(isnumeric('123'))      # True
    print(isnumeric('-123.45'))  # True
    print(isnumeric('+3.14'))    # True
    print(isnumeric('$99.95'))   # False
TrustyTony 888 ex-Moderator Team Colleague Featured Poster

The test is quite limited as can be seen from these numbers, not accepted:

1e3
2+4j
0b01101
0x123abc

and these numbers not numbers

1.2.2.3.4+.+
9-2-34..123

If you want to be very general, you can use test:

def is_numeric(n):
    try:
        n=complex(n)
        return True
    except:
        try:
            n = int(n,0)
            return True
        except:
            return False


for t in '''1e3
2+4j
0b01101
0x123abc
23E23
-23e01
1.2.2.3.4+.+
9-2-34..123
'''.splitlines():
    print t, is_numeric(t)

Output

1e3 True
2+4j True
0b01101 True
0x123abc True
23E23 True
-23e01 True
1.2.2.3.4+.+ False
9-2-34..123 False
Ene Uran 638 Posting Virtuoso

However,
print float('0x123abc')
does not work

So maybe this would be better:

def is_float(s):
    try:
        float(s)
        return True
    except:
        return False

for s in ['1e3', '+3.14', '-77', '0x123abc']:
    if is_float(s):
        print float(s)
    else:
        print s + ' value gives float() error'
ZZucker 342 Practically a Master Poster

I think the problem is:
isnumeric for what purpose?

HiHe 174 Junior Poster

Or use something like this:

mixed_numeric_list =['1e3', '+3.14', '-77', '0x123abc', '0b1111']
numeric_list = [eval(n) for n in mixed_numeric_list]
print(numeric_list)

'''
[1000.0, 3.14, -77, 1194684, 15]
'''
robinlrandall 0 Newbie Poster

How about using regular expressions?
e.g.
/(binary)|(octal)|(hexidecimal)|(decimal)|scientific| ...)/i

/(0b[01]+)|0[0-7]+)|0x[0-9a-f]+)|([+-]?(\d{1,3},?)*(\d{1,3}?[.]?[\d]*)(e[+-][\d]+)?/i    

Or something like that. Just make sure you test it well!
It seems most people forgot that we write "1,000,000" with 2 commas.
RR

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

A mildly more fool proved version ...

''' isnumeric.py
test a numeric string s if it's usable for int(s) or float(s)
'''

def isnumeric(s):
    '''returns True if string s is numeric'''
    return all(c in "0123456789.+-" for c in s) and any(c in "0123456789" for c in s)

# test module ...
if __name__ == '__main__':
    print(isnumeric('123'))      # True
    print(isnumeric('-123.45'))  # True
    print(isnumeric('+3.14'))    # True
    print(isnumeric('$99.95'))   # False
    print(isnumeric('.'))        # False

The challenge might be to make it moron proved.

robinlrandall 0 Newbie Poster

Shouldn't we add ',' to get

print(isnumeric('1,234'))      # True

Is that moron-proof?

TrustyTony 888 ex-Moderator Team Colleague Featured Poster

OK, here then also fooler proofed one. Recursion rocks, sometimes, even in Python!

def is_floating(f, sign_ok=True):
    f = f.strip()
    if not f or f == '.':
        return False
    elif f[0] in '+-' and sign_ok:
        # sign_ok to False if only accept one sign
        return is_floating(f[1:], sign_ok=False)
    elif '.' in f:
        f = f.split('.')
        return not f[0] or f[0].isdigit() and (not f[1] or f[1].isdigit()) if len(f) == 2 else False
    else:
        return f.isdigit()

if __name__ == '__main__':
    for f in ('123','-123.45', '+3.14', '+3.', '+.3', '$99.95', '.', '2.4.3',
                '++2.4.3','2.4+'):
        print('%s => %s' % (f, is_floating(f)))

"""Output:
123 => True
-123.45 => True
+3.14 => True
+3. => True
+.3 => True
$99.95 => False
. => False
2.4.3 => False
++2.4.3 => False
2.4+ => False
"""
Gribouillis 1,391 Programming Explorer Team Colleague

Hm. I have an old regex in my files which handles also the exponential part

import re

_fregex = re.compile(r"^[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$")

def is_floating(f):
    return bool(_fregex.match(f.strip()))


if __name__ == '__main__':
    for f in ('123','-123.45', '+3.14', '+3.', '+.3', '$99.95', '.', '2.4.3',
                '++2.4.3','2.4+'):
        print('%s => %s' % (f, is_floating(f)))

"""
123 => True
-123.45 => True
+3.14 => True
+3. => True
+.3 => True
$99.95 => False
. => False
2.4.3 => False
++2.4.3 => False
2.4+ => False
"""
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Not sure how to handle the comma that is used in some countries as a decimal point.
We have to make sure the numeric string can be converted to a float.
For instance in the US the comma is a "thousand separator".

Gribouillis 1,391 Programming Explorer Team Colleague

Not sure how to handle the comma that is used in some countries as a decimal point.

We could have a concept of "dialect" like the csv module, with fields like "thousand_sep", "decimal_pt".
In the business_fr dialect, thousand_sep would be a space and decimal_pt a comma.

BearofNH 104 Posting Whiz

However,
print float('0x123abc')
does not work

Isn't this a bug in Python?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.