So a user will input a string value in binary format. i.e. '01000001'
I want to check the value they enter to see if it:
has only eight characters.
is a string type
and only contains '0's or '1's
preferably to be done with a function that takes in the user value so that i can call it whenever. Returns false if conditions are not met.
this is what i came up with so far...
size = len(teststring)
teststring = '11111111'
def typecheck(value):
if type(user_input) == type(teststring) and len(user_input) == size and contains only 1 | 0
return
You can use regex matching here:
reg = re.compile(r'^[01]{8}$')
def typecheck(value):
return isinstance(value, str) and bool(reg.match(value))
Or since you want to check for binary format number, how about converting it to int with base 2, and see if it's a valid conversion:
def typecheck(value):
try:
return len(value) == 8 and bool(int(value, 2))
except TypeError, ValueError:
return False
No need for regex
You could use str.strip() and strip all 1 and 0 from end and beginning and check.
Code:
check = "11101110"
if isinstance(check,str) and len(check)==8 and check.strip("01")=='':
print "yes"
Output:
yes
This can be done with one if statement. If the regex doesn't find a match it will return None which evaluates to False in a truth test.
import re
def check_input(user_input):
if not re.match(r'^[01]{8}$', user_input):
it doesn't meet requirements do something
Say I have the function:
def foo(i):
if i == False:
return 1, 2
else:
return 1
I want to check if two items were returned from the function, or just one - how do I do this?
You could check the length of the returned value, and catch a TypeError in case you have an int.
ret = foo(i)
try:
if len(ret) == 2:
print "It's a tuple!"
else:
print "Maybe it's a list?"
except TypeError:
print "It's probably an int!"
Note that if you returned a list, then len() would work correctly instead of throwing a TypeError, and you have more conditions to check for. But if you know that it will be either a tuple or a single integer, this should work.
It's easier to ask forgiveness than permission, as they say.
Keep in mind that if i is True, then you return an integer. Otherwise you return a tuple. So you can write a test like this:
def footest(i):
if isinstance(foo(i),int):
print "one item was returned!"
else:
print "two items were returned!"
Here, isinstance is a type-check, a preferred version of type(foo(i))==int.
i think depending on how you receive your return, you might have an error. If you're receiving it correctly, the easy way in this very specific case of one or two would be to check if the second element exists i.e. if answer(2): or check then length of your tuple, answer.length.
Your current code returns an int if i is True, otherwise it returns a tuple. You can check for type with isinstance
>>> isinstance(foo(False), int) # foo(False) is a tuple, so this should be False
False
>>> isinstance(foo(True), int) # foo(True) is an int, so this should be True
True
s="(8+(2+4))"
def checker(n):
if len(n) == 0:
return True
if n[0].isdigit==True:
if n[1].isdigit==True:
return False
else:
checker(n[1:])
else:
checker(n[1:])
This is what I have so far. Simple code, trying to see if a string meets the following conditions.
However when i perform checker(s) i get:
True
IndexError: string index out of range
Any help? Thanks in advance
Edit: The function's purpose is to produce true if the string contains only single digit numbers, and false if 2 or more-figured digits exist in the string.
When the length of n is 0, the n[0] part is going to raise an error because the string in empty. You should add a return statement there instead of print.
def checker(n):
if len(n) < 2:
return True
if n[0] in x:
Note that the conditions must be len(n) < 2 otherwise you'll get an error on n[1] when the length of string is 1.
Secondly you're trying to match characters to a list which contains integers, so the in checks are always going to be False. Either convert the list items to string or better use str.isdigit.
>>> '1'.isdigit()
True
>>> ')'.isdigit()
False
>>> '12'.isdigit()
True
Update:
You can use regex and all for this:
>>> import re
def check(strs):
nums = re.findall(r'\d+',strs)
return all(len(c) == 1 for c in nums)
...
>>> s="(8+(2+4))"
>>> check(s)
True
>>> check("(8+(2+42))")
False
Working version of your code:
s="(8+(2+4))"
def checker(n):
if not n: #better than len(n) == 0, empty string returns False in python
return True
if n[0].isdigit(): #str.digit is a method and it already returns a boolean value
if n[1].isdigit():
return False
else:
return checker(n[1:]) # use return statement for recursive calls
# otherwise the recursive calls may return None
else:
return checker(n[1:])
print checker("(8+(2+4))")
print checker("(8+(2+42))")
output:
True
False
You should do return True after the first if statement, not print True. The function continues to run after that statement and hits an error when the input is size 0.
I can't reproduce your error.
I had to fix a few things:
Indentation, which I'm guessing was just a problem pasting into the page
.isdigit() is a function; calling .isdigit==True is going to compare a function object with True, which is never going to be true. I changed .isdigit==True to .isdigit()
I made sure return value gets bubbled up - without this, the recursion completes okay but the outermost function just returns "None".
Aside from that, a few print statements show that this is working as expected
s="(8+(2+4))"
t="(8+(20+4))"
def checker(n):
print "checking %s" % n
if len(n) == 0:
print "Returning true"
return True
if n[0].isdigit():
if n[1].isdigit():
print "returning false"
return False
else:
return checker(n[1:])
else:
return checker(n[1:])
print checker(s)
print checker(t)
Output:
checking (8+(2+4))
checking 8+(2+4))
checking +(2+4))
checking (2+4))
checking 2+4))
checking +4))
checking 4))
checking ))
checking )
checking
Returning true
True
checking (8+(20+4))
checking 8+(20+4))
checking +(20+4))
checking (20+4))
checking 20+4))
returning false
False
I've got some Python code that runs through a list of strings and converts them to integers or floating point numbers if possible. Doing this for integers is pretty easy
if element.isdigit():
newelement = int(element)
Floating point numbers are more difficult. Right now I'm using partition('.') to split the string and checking to make sure that one or both sides are digits.
partition = element.partition('.')
if (partition[0].isdigit() and partition[1] == '.' and partition[2].isdigit())
or (partition[0] == '' and partition[1] == '.' and partition[2].isdigit())
or (partition[0].isdigit() and partition[1] == '.' and partition[2] == ''):
newelement = float(element)
This works, but obviously the if statement for that is a bit of a bear. The other solution I considered is to just wrap the conversion in a try/catch block and see if it succeeds, as described in this question.
Anyone have any other ideas? Opinions on the relative merits of the partition and try/catch approaches?
I would just use..
try:
float(element)
except ValueError:
print "Not a float"
..it's simple, and it works. Note that it will still throw OverflowError if element is e.g. 1<<1024.
Another option would be a regular expression:
import re
if re.match(r'^-?\d+(?:\.\d+)$', element) is None:
print "Not float"
Python3 method to check for float:
def is_float(element: any) -> bool:
#If you expect None to be passed:
if element is None:
return False
try:
float(element)
return True
except ValueError:
return False
Python2 version of the above: How do I parse a string to a float or int?
Always do unit testing. What is and is not a float may surprise you:
Command to parse Is it a float? Comment
-------------------------------------- --------------- ------------
print(isfloat("")) False
print(isfloat("1234567")) True
print(isfloat("1_2_3.4")) True 123.4, underscores ignored
print(isfloat("NaN")) True nan is also float
print(isfloat("123.456")) True
print(isfloat("123.E4")) True
print(isfloat(".1")) True
print(isfloat("6.523537535629999e-07")) True
print(isfloat("6e777777")) True This is same as Inf
print(isfloat("-iNF")) True
print(isfloat("1.797693e+308")) True
print(isfloat("infinity")) True
print(isfloat("1,234")) False
print(isfloat("NULL")) False case insensitive
print(isfloat("NaNananana BATMAN")) False
print(isfloat(",1")) False
print(isfloat("123.EE4")) False
print(isfloat("infinity and BEYOND")) False
print(isfloat("12.34.56")) False Two dots not allowed.
print(isfloat("#56")) False
print(isfloat("56%")) False
print(isfloat("0E0")) True
print(isfloat("x86E0")) False
print(isfloat("86-5")) False
print(isfloat("True")) False Boolean is not a float.
print(isfloat(True)) True Boolean is a float
print(isfloat("+1e1^5")) False
print(isfloat("+1e1")) True
print(isfloat("+1e1.3")) False
print(isfloat("+1.3P1")) False
print(isfloat("-+1")) False
print(isfloat("(1)")) False brackets not interpreted
Sinking exceptions like this is bad, because killing canaries is bad because the float method can fail for reasons other than user input. Do not be using code like this on life critical software. Also python has been changing its contract on what unicode strings can be promoted to float so expect this behavior of this code to change on major version updates.
'1.43'.replace('.','',1).isdigit()
which will return true only if there is one or no '.' in the string of digits.
'1.4.3'.replace('.','',1).isdigit()
will return false
'1.ww'.replace('.','',1).isdigit()
will return false
TL;DR:
If your input is mostly strings that can be converted to floats, the try: except: method is the best native Python method.
If your input is mostly strings that cannot be converted to floats, regular expressions or the partition method will be better.
If you are 1) unsure of your input or need more speed and 2) don't mind and can install a third-party C-extension, fastnumbers works very well.
There is another method available via a third-party module called fastnumbers (disclosure, I am the author); it provides a function called isfloat. I have taken the unittest example outlined by Jacob Gabrielson in this answer, but added the fastnumbers.isfloat method. I should also note that Jacob's example did not do justice to the regex option because most of the time in that example was spent in global lookups because of the dot operator... I have modified that function to give a fairer comparison to try: except:.
def is_float_try(str):
try:
float(str)
return True
except ValueError:
return False
import re
_float_regexp = re.compile(r"^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$").match
def is_float_re(str):
return True if _float_regexp(str) else False
def is_float_partition(element):
partition=element.partition('.')
if (partition[0].isdigit() and partition[1]=='.' and partition[2].isdigit()) or (partition[0]=='' and partition[1]=='.' and partition[2].isdigit()) or (partition[0].isdigit() and partition[1]=='.' and partition[2]==''):
return True
else:
return False
from fastnumbers import isfloat
if __name__ == '__main__':
import unittest
import timeit
class ConvertTests(unittest.TestCase):
def test_re_perf(self):
print
print 're sad:', timeit.Timer('ttest.is_float_re("12.2x")', "import ttest").timeit()
print 're happy:', timeit.Timer('ttest.is_float_re("12.2")', "import ttest").timeit()
def test_try_perf(self):
print
print 'try sad:', timeit.Timer('ttest.is_float_try("12.2x")', "import ttest").timeit()
print 'try happy:', timeit.Timer('ttest.is_float_try("12.2")', "import ttest").timeit()
def test_fn_perf(self):
print
print 'fn sad:', timeit.Timer('ttest.isfloat("12.2x")', "import ttest").timeit()
print 'fn happy:', timeit.Timer('ttest.isfloat("12.2")', "import ttest").timeit()
def test_part_perf(self):
print
print 'part sad:', timeit.Timer('ttest.is_float_partition("12.2x")', "import ttest").timeit()
print 'part happy:', timeit.Timer('ttest.is_float_partition("12.2")', "import ttest").timeit()
unittest.main()
On my machine, the output is:
fn sad: 0.220988988876
fn happy: 0.212214946747
.
part sad: 1.2219619751
part happy: 0.754667043686
.
re sad: 1.50515985489
re happy: 1.01107215881
.
try sad: 2.40243887901
try happy: 0.425730228424
.
----------------------------------------------------------------------
Ran 4 tests in 7.761s
OK
As you can see, regex is actually not as bad as it originally seemed, and if you have a real need for speed, the fastnumbers method is quite good.
If you cared about performance (and I'm not suggesting you should), the try-based approach is the clear winner (compared with your partition-based approach or the regexp approach), as long as you don't expect a lot of invalid strings, in which case it's potentially slower (presumably due to the cost of exception handling).
Again, I'm not suggesting you care about performance, just giving you the data in case you're doing this 10 billion times a second, or something. Also, the partition-based code doesn't handle at least one valid string.
$ ./floatstr.py
F..
partition sad: 3.1102449894
partition happy: 2.09208488464
..
re sad: 7.76906108856
re happy: 7.09421992302
..
try sad: 12.1525540352
try happy: 1.44165301323
.
======================================================================
FAIL: test_partition (__main__.ConvertTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./floatstr.py", line 48, in test_partition
self.failUnless(is_float_partition("20e2"))
AssertionError
----------------------------------------------------------------------
Ran 8 tests in 33.670s
FAILED (failures=1)
Here's the code (Python 2.6, regexp taken from John Gietzen's answer):
def is_float_try(str):
try:
float(str)
return True
except ValueError:
return False
import re
_float_regexp = re.compile(r"^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$")
def is_float_re(str):
return re.match(_float_regexp, str)
def is_float_partition(element):
partition=element.partition('.')
if (partition[0].isdigit() and partition[1]=='.' and partition[2].isdigit()) or (partition[0]=='' and partition[1]=='.' and pa\
rtition[2].isdigit()) or (partition[0].isdigit() and partition[1]=='.' and partition[2]==''):
return True
if __name__ == '__main__':
import unittest
import timeit
class ConvertTests(unittest.TestCase):
def test_re(self):
self.failUnless(is_float_re("20e2"))
def test_try(self):
self.failUnless(is_float_try("20e2"))
def test_re_perf(self):
print
print 're sad:', timeit.Timer('floatstr.is_float_re("12.2x")', "import floatstr").timeit()
print 're happy:', timeit.Timer('floatstr.is_float_re("12.2")', "import floatstr").timeit()
def test_try_perf(self):
print
print 'try sad:', timeit.Timer('floatstr.is_float_try("12.2x")', "import floatstr").timeit()
print 'try happy:', timeit.Timer('floatstr.is_float_try("12.2")', "import floatstr").timeit()
def test_partition_perf(self):
print
print 'partition sad:', timeit.Timer('floatstr.is_float_partition("12.2x")', "import floatstr").timeit()
print 'partition happy:', timeit.Timer('floatstr.is_float_partition("12.2")', "import floatstr").timeit()
def test_partition(self):
self.failUnless(is_float_partition("20e2"))
def test_partition2(self):
self.failUnless(is_float_partition(".2"))
def test_partition3(self):
self.failIf(is_float_partition("1234x.2"))
unittest.main()
Just for variety here is another method to do it.
>>> all([i.isnumeric() for i in '1.2'.split('.',1)])
True
>>> all([i.isnumeric() for i in '2'.split('.',1)])
True
>>> all([i.isnumeric() for i in '2.f'.split('.',1)])
False
Edit: Im sure it will not hold up to all cases of float though especially when there is an exponent. To solve that it looks like this. This will return True only val is a float and False for int but is probably less performant than regex.
>>> def isfloat(val):
... return all([ [any([i.isnumeric(), i in ['.','e']]) for i in val], len(val.split('.')) == 2] )
...
>>> isfloat('1')
False
>>> isfloat('1.2')
True
>>> isfloat('1.2e3')
True
>>> isfloat('12e3')
False
Simplified version of the function is_digit(str), which suffices in most cases (doesn't consider exponential notation and "NaN" value):
def is_digit(str):
return str.lstrip('-').replace('.', '').isdigit()
This regex will check for scientific floating point numbers:
^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$
However, I believe that your best bet is to use the parser in a try.
If you don't need to worry about scientific or other expressions of numbers and are only working with strings that could be numbers with or without a period:
Function
def is_float(s):
result = False
if s.count(".") == 1:
if s.replace(".", "").isdigit():
result = True
return result
Lambda version
is_float = lambda x: x.replace('.','',1).isdigit() and "." in x
Example
if is_float(some_string):
some_string = float(some_string)
elif some_string.isdigit():
some_string = int(some_string)
else:
print "Does not convert to int or float."
This way you aren't accidentally converting what should be an int, into a float.
I used the function already mentioned, but soon I notice that strings as "Nan", "Inf" and it's variation are considered as number. So I propose you improved version of the function, that will return false on those type of input and will not fail "1e3" variants:
def is_float(text):
# check for nan/infinity etc.
if text.isalpha():
return False
try:
float(text)
return True
except ValueError:
return False
You can use the try-except-else clause , this will catch any conversion/ value errors raised when the value passed cannot be converted to a float
def try_parse_float(item):
result = None
try:
float(item)
except:
pass
else:
result = float(item)
return result
a simple function that get you the type of number without try and except operation
def number_type(number):
if number.isdigit():
return int(number)
elif number.replace(".","").isdigit():
return float(number)
else:
return(type(number))
I was looking for some similar code, but it looks like using try/excepts is the best way.
Here is the code I'm using. It includes a retry function if the input is invalid. I needed to check if the input was greater than 0 and if so convert it to a float.
def cleanInput(question,retry=False):
inputValue = input("\n\nOnly positive numbers can be entered, please re-enter the value.\n\n{}".format(question)) if retry else input(question)
try:
if float(inputValue) <= 0 : raise ValueError()
else : return(float(inputValue))
except ValueError : return(cleanInput(question,retry=True))
willbefloat = cleanInput("Give me the number: ")
Try to convert to float. If there is an error, print the ValueError exception.
try:
x = float('1.23')
print('val=',x)
y = float('abc')
print('val=',y)
except ValueError as err:
print('floatErr;',err)
Output:
val= 1.23
floatErr: could not convert string to float: 'abc'
Passing dictionary as argument it will convert strings which can be converted to float and will leave others
def covertDict_float(data):
for i in data:
if data[i].split(".")[0].isdigit():
try:
data[i] = float(data[i])
except:
continue
return data
I tried some of the above simple options, using a try test around converting to a float, and found that there is a problem in most of the replies.
Simple test (along the lines of above answers):
entry = ttk.Entry(self, validate='key')
entry['validatecommand'] = (entry.register(_test_num), '%P')
def _test_num(P):
try:
float(P)
return True
except ValueError:
return False
The problem comes when:
You enter '-' to start a negative number:
You are then trying float('-') which fails
You enter a number, but then try to delete all the digits
You are then trying float('') which likewise also fails
The quick solution I had is:
def _test_num(P):
if P == '' or P == '-': return True
try:
float(P)
return True
except ValueError:
return False
It seems many regex given miss one thing or another. This has been working for me so far:
(?i)^\s*[+-]?(?:inf(inity)?|nan|(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*$
It allows for infinity (or inf) with sign, nan, no digit before the
decimal, and leading/trailing spaces (if desired). The ^ and $ are
needed to keep from partially matching something like 1.2f-2 as 1.2.
You could use [ed] instead of just e if you need to parse some files
where D is used for double-precision scientific notation. You would
want to replace it afterward or just replace them before checking since
the float() function won't allow it.
I found a way that could also work. need to verify this. first time putting something here.
def isfloat(a_str):
try:
x=float(a_str)
if x%1 == 0:
return False
elif x%1 != 0: #an else also do
return True
except Exception as error:
return False
This works like a charm:
[dict([a,int(x) if isinstance(x, str)
and x.isnumeric() else float(x) if isinstance(x, str)
and x.replace('.', '', 1).isdigit() else x] for a, x in json_data.items())][0]
I've written my own functions. Instead of float(value), I use floatN() or floatZ(). which return None or 0.0 if the value can't be cast as a float. I keep them in a module I've called safeCasts.
def floatN(value):
try:
if value is not None:
fvalue = float(value)
else:
fvalue = None
except ValueError:
fvalue = None
return fvalue
def floatZ(value):
try:
if value is not None:
fvalue = float(value)
else:
fvalue = 0.0
except ValueError:
fvalue = 0.0
return fvalue
In other modules I import them
from safeCasts import floatN, floatZ
then use floatN(value) or floatZ(value) instead of float(). Obviously, you can use this technique for any cast function you need.
It's a simple, yet interesting question. Solution presented below works fine for me:
import re
val = "25,000.93$"
regex = r"\D"
splitted = re.split(regex, val)
splitted = list(filter(str.isdecimal, splitted))
if splitted:
if len(splitted) > 1:
splitted.insert(-1, ".")
try:
f = float("".join(splitted))
print(f, "is float.")
except ValueError:
print("Not a float.")
else:
print("Not a float.")
Important note: this solution is based on assumption that the last value in splitted contains decimal places.
You can create a function isfloat(), and use in place of isdigit() for both integers and floats, but not strings as you expect.
a = raw_input('How much is 1 share in that company? \n')
def isfloat(num):
try:
float(num)
return True
except:
return False
while not isfloat(a):
print("You need to write a number!\n")
a = raw_input('How much is 1 share in that company? \n')
We can use regex as:
import re
if re.match('[0-9]*.?[0-9]+', <your_string>):
print("Its a float/int")
else:
print("Its something alien")
let me explain the regex in english,
* -> 0 or more occurence
+ -> 1 or more occurence
? -> 0/1 occurence
now, lets convert
'[0-9]* -> let there be 0 or more occurence of digits in between 0-9
\.? -> followed by a 0 or one '.'(if you need to check if it can be int/float else we can also use instead of ?, use {1})
[0-9]+ -> followed by 0 or more occurence of digits in between 0-9
str(strval).isdigit()
seems to be simple.
Handles values stored in as a string or int or float