This question already has answers here:
How to check if a user input is a float
(6 answers)
Closed 4 years ago.
This code returns False, but when I delete point from float it becomes True and I'm trying to understand why. Explain please
def isDigit(string):
string = string.strip()
if string[:1] == "-":
cuted = string[1:]
if cuted.isdigit():
return True
else:
return False
elif string.isdigit():
return True
else:
return False
print isDigit("-234.4")
also I know my code is not the best and I wonder how can I make it better
isdigit only checks if all the characters are digits (e.g. 0, 1, ... 9).
Therefore the string 234.4 will return False because it also contains a decimal point ., that is not a digit.
help("".isdigit)
will tell you that to be True all characters must be digits and there must be at least one character.
You could use a regular expression to do this kind of checking, for example with something like:
import re
def isnumber(x):
return re.match("-?[0-9]+([.][0-9]+)?$", x) is not None
that will accept an optional minus sign, followed by a sequence of one or more digits optionally followed by a decimal dot and more digits.
Note that floating point numbers can be accepted by a much wider syntax, including scale exponent and missing parts before and after the decimal point so don't be this strict if you're validating output from a computer. Depending on the context it may be however meaningful to refuse things like 1e4 as numbers from a human.
Let's step through your code.
if string[:1] == "-":
string[:1] means "make a string with characters from the start of string up to (but not including) index 1." If your string is "foobar", string[:1] will be "f". In your example, string[:1] will be "-"
cuted = string[1:]
This will do the opposite, producing a string that contains everything but the first character. In this case, cuted would be "234.4"
if cuted.isdigit():
return True
else:
return False
This will test if cuted is made up only of numbers. In our case, this is false, because it contains a decimal point. False is returned.
elif string.isdigit():
return True
else:
return False
If the first character was not "-", this is run instead. If you supplied "234.4", this case would be reached, and the test would fail (because "234.4" contains a decimal point), so False would be returned.
Your code appears to be valid if what you wanted was:
123.3 -> False
-123.3 -> False
123 -> True
-123 -> True
On the other hand, if you want your function to say all four of those are numbers, then you need to modify your code. The one way (probably not the best!) to do that would be to have a test case that does something like this:
If I split this string on ".", do I get two strings?
If so, are both pieces of the string digits?
If so, the string is a number.
It's not clear exactly what behavior you want.
Related
I want to check a 'x' string whether it is a digit or not in advance.
'1' is naturally a digit.
But and I will use ① what is calld a string number very much.
I don't know the range of string numbers IDE judges as a digit.
'①'.isdigit() returns True.
'⑴'.isdigit() returns True.
'ⅰ' or 'Ⅰ' returns False.
'㈠' returns False. (kanji version of (1) )
'❶' returns True.
I want to do like this.
for s in data:
if s.isdigit():
int_ = int(s)
If I accept '①', int will throw an error. Now, I write try:except for it.
Because I'm a japanese, I often use '①' or '⑴'
How to distinguish isdigit or not isdigit in advance?
Should I rely on try:except or counting all of them in advance?
regular expression?
The main problem is I don't know what is judged as a digit.
data = ["1", "23", "345", "①", "(1)", "(2)"]
This data is dynamic value. It will be changed every time.
Moreover, the string like this may expand in the future.
I hope the string of isdigit() == True is accepted by int().
I don't have an urgent problem because of try: except.
I believe that the str.isdecimal method fits your requirements. It excludes strings like '①', but includes other strings like '١' which are accepted by int.
>>> int('١')
1
I've been re-learning python over the last 2 days, and decided to use regular expression [here out referred to as RE] for the first time (in conjunction with tkinter), its exceptionally confusing.
I'm trying to check every character in a string is a number or period, however this has proven difficult for me to wrap my head around.
Here is the code:
def matchFloat(string, search=re.compile(r'[0-9.]').search):
return bool(search(string))
def matchInt(string, search=re.compile(r'[0-9]').search):
return bool(search(string))
def callbackFloat(P):
if matchFloat(P) or P == "":
return True
else:
return False
def callbackInt(P):
if matchInt(P) or P == "":
return True
else:
return False
The first character entered into my enter box [see below] is forced to be a number or . (in the Floats case), however RE search() only requires 1 of the characters to meet the conditions for it to return True.
So in short, Is there a way to only return True if every character in a string conforms to the set RE conditions?
Any help is appreciated, thank you in advanced!
Images:
As you can see, I'm quite new to this.
Disallowed Characters In Box
This thread may be helpful as it covers the topic of tkinter input validation.
However, quick answer to your question:
search(r"^[0-9]+$", string)
would match an integer string. The RE pattern means "one or more digits, extending from the beginning of the string to the end". This can also be shortened to r"^\d+$".
You could also use the re.fullmatch() method:
fullmatch(r"[0-9]+", string)
And for the sake of completeness, I'll point out that you don't need to do this work yourself. You can determine if a string represents an integer with string.isdigit(), string.isdecimal(), or string.isnumeric() methods.
As for checking whether a string is a float, the Pythonic way is to just try converting to a float and catch the exception if it fails:
try:
num = float(string)
except:
print("not a float")
def is_valid_zip(zip_code):
"""Returns whether the input string is a valid (5 digit) zip code
"""
if (len(zip_code) == 5) and (str.isnumeric == True):
return True
else :
return False
First of all, it should be str.isnumeric() == True as that's calling the isnumeric function. Second of all you should be really using str.isdigit().
str.isnumeric()
In Python, decimal characters (like: 0, 1, 2..), digits (like: subscript, superscript), and characters having Unicode numeric value property (like: fraction, roman numerals, currency numerators) are all considered numeric characters. Therefore even japanese character for 1, 2 and 3 would pass this check.
str.isdigit()
On the other hand isdigit() will only return True if all characters in a string are digits. If not, it returns False.
source: https://www.programiz.com/python-programming/methods/string/isdigit
A few point to discuss. Regarding your condition:
str.isnumeric == True
That thing on the left side is the function itself, not a call to the function giving a result, the latter would be some_string.isnumeric().
The chances of the function object being equal to true are somewhere between zero and a very, very small number :-)
It's also redundant to compare boolean values against boolean constants since the result of the comparison is just another boolean value. Where do you stop in that case? For example:
(((some_bool_value == True) == True) == True) != False ...
Another point, the code form if cond then return true else return false can be replaced with the much less verbose return cond.
And also keep in mind that isnumeric() allows other things than raw digits, like ¾. If you just want the digits, you're probably better off with another method. You may be tempted to instead use isdigit(), but even that allows other things than just what most would consider "normal" digits, such as allowing "90²10" as a postal code, presumably the much trendier part of Beverly Hills :-).
If you only wanted the raw digits 0-9 (which is probably the case with US postal codes like you seem to be targeting), neither isnumeric() nor isdigit() is really suitable.
An implementation of the function, taking all that into account, could be as follows:
def is_valid_zip(zip_code):
if len(zip_code) != 5:
return False
return all([x in "1234567890" for x in zip_code])
it should be zip_code.isnumeric() not str.isnumeric
Also, why don't you use regex:
import re
RE_ZIP_CODE = re.compile(r'^[0-9]{5}$') # or r'^\d{5}$' for all digit characters
def is_valid_zip(zip_code):
return RE_ZIP_CODE.search(zip_code) is not None
This should work
def is_valid_zip(zip_code):
"""Returns whether the input string is a valid (5 digit) zip code
"""
if len(zip_code) == 5 and zip_code.isnumeric():
return True
else:
return False
print(is_valid_zip("98909"))
This question already has answers here:
Formatting floats without trailing zeros
(21 answers)
Closed 5 years ago.
I have a function which trims trailing decimal places from integers and converts it to a string. For example trim(1.0) outputs '1'.
this is my code:
def trim(num):
num1 = str(num)
try:
if '.0' in num1:
return num1[:num1:rfind('.0')]
return num1
except Exception:
pass
While this takes care of numbers with 1 trailing decimal places perfectly, it does not work with more decimal places (such as 2.000). Is there a way to trim all of the trailing decimal places?
First of all, you code is faulty. If I take your code and run this:
print(your_trim(1.1))
print(your_trim(1.0566))
print(your_trim('1cm'))
The output is:
1.1
1 <-- this is dangerous, the value is 1.0566!
1cm <-- this is not even a number
As the commenters mentioned, you may be mismatching floats and integers. As the name implies, an integer does not have decimal places. If your goal ist to strip trailing zeros (for whatever reason) and not round a float to an int, you might use something like this approach:
def strip_trailing_zeroes(num):
if isinstance(num, float):
if int(num) == num:
return int(num)
else:
return num
else:
raise ValueError("Parameter is not a float")
Testing the code:
print(strip_trailing_zeroes(1.1))
print(strip_trailing_zeroes(1.0566))
print(strip_trailing_zeroes(1.000))
print(strip_trailing_zeroes('1cm'))
Returns the output:
1.1
1.0566
1
Exception with "ValueError: Parameter is not a float"
As the other commenters put it, I can't imagine of a use case for this.
What you might be after, is trimming trailing zeros from a "string representation" of a float. For this, a simple regular expression replacement is enough:
# match a decimal point, followed by one or more zeros
# followed by the end of the input
print(re.sub('\.0+$', '', '2.000'))
Along the lines of my previous question, How do I convert unicode characters to floats in Python? , I would like to find a more elegant solution to calculating the value of a string that contains unicode numeric values.
For example, take the strings "1⅕" and "1 ⅕". I would like these to resolve to 1.2
I know that I can iterate through the string by character, check for unicodedata.category(x) == "No" on each character, and convert the unicode characters by unicodedata.numeric(x). I would then have to split the string and sum the values. However, this seems rather hacky and unstable. Is there a more elegant solution for this in Python?
I think this is what you want...
import unicodedata
def eval_unicode(s):
#sum all the unicode fractions
u = sum(map(unicodedata.numeric, filter(lambda x: unicodedata.category(x)=="No",s)))
#eval the regular digits (with optional dot) as a float, or default to 0
n = float("".join(filter(lambda x:x.isdigit() or x==".", s)) or 0)
return n+u
or the "comprehensive" solution, for those who prefer that style:
import unicodedata
def eval_unicode(s):
#sum all the unicode fractions
u = sum(unicodedata.numeric(i) for i in s if unicodedata.category(i)=="No")
#eval the regular digits (with optional dot) as a float, or default to 0
n = float("".join(i for i in s if i.isdigit() or i==".") or 0)
return n+u
But beware, there are many unicode values that seem to not have a numeric value assigned in python (for example ⅜⅝ don't work... or maybe is just a matter with my keyboard xD).
Another note on the implementation: it's "too robust", it will work even will malformed numbers like "123½3 ½" and will eval it to 1234.0... but it won't work if there are more than one dots.
>>> import unicodedata
>>> b = '10 ⅕'
>>> int(b[:-1]) + unicodedata.numeric(b[-1])
10.2
define convert_dubious_strings(s):
try:
return int(s)
except UnicodeEncodeError:
return int(b[:-1]) + unicodedata.numeric(b[-1])
and if it might have no integer part than another try-except sub-block needs to be added.
This might be sufficient for you, depending on the strange edge cases you want to deal with:
val = 0
for c in my_unicode_string:
if unicodedata.category(unichr(c)) == 'No':
cval = unicodedata.numeric(c)
elif c.isdigit():
cval = int(c)
else:
continue
if cval == int(cval):
val *= 10
val += cval
print val
Whole digits are assumed to be another digit in the number, fractional characters are assumed to be fractions to add to the number. Doesn't do the right thing with spaces between digits, repeated fractions, etc.
I think you'll need a regular expression, explicitly listing the characters that you want to support. Not all numerical characters are suitable for the kind of composition that you envision - for example, what should be the numerical value of
u"4\N{CIRCLED NUMBER FORTY TWO}2\N{SUPERSCRIPT SIX}"
???
Do
for i in range(65536):
if unicodedata.category(unichr(i)) == 'No':
print hex(i), unicodedata.name(unichdr(i))
and go through the list defining which ones you really want to support.