I am attempting to do what should be very simple and check to see if a value in an Entry field is a valid and real number. The str.isnumeric() method does not account for "-" negative numbers, or "." decimal numbers.
I tried writing a function for this:
def IsNumeric(self, event):
w = event.widget
if (not w.get().isnumeric()):
if ("-" not in w.get()):
if ("." not in w.get()):
w.delete(0, END)
w.insert(0, '')
This works just fine until you go back and type letters in there. Then it fails.
I researched the possibility of using the .split() method, but I could not figure out a reliable regex to deal for it.
This is a perfectly normal thing that needs to be done. Any ideas?
try:
float(w.get())
except ValueError:
# wasn't numeric
It sounds like you might just need to know whether passing some string to float will give a result (i.e. it is a nice numeric value), or an error (i.e. the string doesn't represent a number). Try this:
def isnum(s):
try:
float(s)
except:
return(False)
else:
return(True)
I realise this is an old question but I've just faced this problem.
You can do something like:
if re.sub("[^0-9\\-\\.]", "", "-0.18"):
Related
I want to get the follow list:
['value1', 'value2', 'value3']
from the next string:
some_option=value1,value2,value3
Is it ugly to use the following code to get this?
some_string = 'some_option=value1,value2,value3'
print(some_string.split('=')[1].split(','))
I don't agree with the "ugly" statement, as that seems perfectly Pythonic to me, and efficient enough for the job at least. IMHO the question of how the code appears doesn't matter as much as whether it's easily understandable to others what the code is doing, and more importantly whether it actually gets the task accomplished - which it certainly does.
A slight change for optimization I would propose is to pass the number of splits to str.split, and then you can safely access the last result rather than the 2nd element:
some_string = 'some_option=value1,value2,value3'
print(some_string.split('=', 1)[-1].split(','))
"Ugly" is a matter of opinion, and can not be answered on stackoverflow.
The real issue with your code however, is that it has no error checking, so if the input string does not contain an = character, you will be indexing a non-existent list member.
If this code is designed for production application and not some personal tool, you should do something like this:
some_string = 'some_option=value1,value2,value3'
try:
print(some_string.split('=')[1].split(','))
except IndexError:
print('Invalid input')
Or, if you just want to skip the bad strings you can put pass in the except clause.
Without knowing more context, it looks fine to me. If you feel bad about the ugliness, one way to improve might be to put that inside a function, such as
def scrape_values(row):
return row.split('=')[1].split(',')
some_string = 'some_option=value1,value2,value3'
print(scrape_values(some_string))
If you give the function a meaningful name, then we can "abstract away" the ugliness
I am writing a small function that turns a integer into its reciprocal in its fraction form. This is how I've defined my function so far:
def reciprocal (number):
return "1/",number
This sort of works but the problem is that it doesn't print the answer on the screen as I'd like to because say i did print reciprocal(3) it would show ('1/', 3) on the screen instead of 1/3. I have tried all sorts of combinations of speech marks and brackets in the code but the answer has still got extra brackets and back-ticks around it. I am using python 2.7.10, is there any way to get rid of these? Or is there any other simple way to express an integer as its reciprocal in fraction form that would get rid of them? Thank you
Yes. Because what this line is actually doing is returning a tuple:
return "1/",number
If you simply print:
type(reciprocal(3))
You will see the result will be tuple.
In order to keep the functionality of:
print(reciprocal(3))
You would want to do something like this instead:
return "1/{}".format(number)
Now, the above will actually return you a string instead of a tuple. The above is using the string format method, which you can read about here. Ultimately what you are doing is creating a string that will look like 1/x, where x will be number. The way to denote the x is by using the curly braces which is then used a placeholder that will set whatever you passed to format. Read more in the documentation to understand how it works.
To help expand it, what it actually looks like when separated is this:
s = "1/"
Now, you want to be able to set your argument number. The string object supports several methods, one of which, is format. So you can actually simply call it: s.format(). However, that won't simply work the way you want it. So, per the documentation, in order to use this format method, you need to set in your string where exactly you want to set your argument that you want to place in your string. This is done by using the placeholder characters {} to indicate this. So:
s = "1/"
Will now be
s = "1/{}".format(number)
We set our {} as the placeholder of where we want number to be, and we assigned what will be in that placeholder by passing number to format.
You can further see how now you have a string if you in fact print the type of the result:
print(type(reciprocal(3)))
You will see it is now a str type.
As a note in Python, you can create a tuple with comma separated values:
>>> d = 1, 2
>>> type(d)
<class 'tuple'>
This is exactly why your function returns the tuple, because of the fact you are returning two values simply separated by a comma.
You can try this:
def reciprocal (number):
return "1/{}".format(number)
print reciprocal(4)
print reciprocal(100)
Output:
1/4
1/100
Right now you're returning a tuple made of the string "1/" and your number because of the comma. I think what you want to do is return just a string.
Something like return "1/" + str(number)
I am making a small interactive text game in python.
i need to check if a string, from the user, is 1234 (a number in a string that would work with int() ) or foo (just a string, python would traceback if I called int() on it)
while(True):
IN = input("[Number] >> ")
if(isNumber(IN)):
break
else:
print("Please enter a number.")
continue
IN = int(IN) #guaranteed to work at this point
someFunction(IN)
thanks in advance!
If you want to know if something is "a number in a string, one that would work with int()", you do that by just calling int:
try:
i = int(myvar)
# It's an int, and we have the value if you want it
except ValueError:
# It's not an int
This is a general case of the EAFP principle: It's Easier to Ask Forgiveness than Permission. Instead of trying to guess whether something would fail, it's usually easier to just try it and see if it fails.
That's especially try in cases where trying to guess is more complicated than it looks. For example, people always suggest using the isdigit method here, but that fails in a number of cases. For example:
isdigit is false for negative numbers, because the '-' character is not a digit.
isdigit is false for numbers with trailing whitespace (e.g., because you're not rstripping newlines from your input).
isdigit is true for hundreds of non-western digits and special-form digits that can't be used with int.
int has changed its rules at least twice between Python 2.0 and 3.4, and could always change again.
You probably could come up with a complicated rule that was exactly the same as "would work with int()" as interpreted in some specific Python version, but why, when int is obviously guaranteed to always do the same thing as int?
I am trying to create a way to proofread command console input and check to make sure that the string is an rgb hex string. (Ex: #FAF0E6) Currently I am working with a try: except: block.
def isbgcolor(bgcolor):
#checks to see if bgcolor is binary
try:
float(bgcolor)
return True
except ValueError:
return False
I tried also using a .startswith('#'). I have seen examples of how to write this function in Java but I'm still a beginner and Python's all I know. Help?
Normally, the best way to see if a string matches some simple format is to actually try to parse it. (Especially if you're only checking so you can then parse it if valid, or print an error if not.) So, let's do that.
The standard library is full of all kinds of useful things, so it's always worth searching. If you want to parse a hex string, the first thing that comes up is binascii.unhexlify. We want to unhexlify everything after the first # character. So:
import binascii
def parse_bgcolor(bgcolor):
if not bgcolor.startswith('#'):
raise ValueError('A bgcolor must start with a "#"')
return binascii.unhexlify(bgcolor[1:])
def is_bgcolor(bgcolor):
try:
parse_bgcolor(bgcolor)
except Exception as e:
return False
else:
return True
This accepts 3-character hex strings (but then so do most data formats that use #-prefixed hex RGB), and even 16-character ones. If you want to add a check for the length, you can add that. Is the rule == 6 or in (3, 6) or % 3 == 0? I don't know, but presumably you do if you have a rule you want to add.
If you start using parse_bgcolor, you'll discover that it's giving you a bytes with 6 values from 0-255, when you really wanted 3 values from 0-65535. You can combine them manually, or you can parse each two-character pair as a number (e.g., with int(pair, 16)), or you can feed the 6-char bytes you already have into, say, struct.unpack('>HHH'). Whatever you need to do is pretty easy once you know exactly what you want to do.
Finally, if you're trying to parse CSS or HTML, things like red or rgb(1, 2, 3) are also valid colors. Do you need to handle those? If so, you'll need something a bit smarter than this. The first thing to do is look at the spec for what you're trying to parse, and work out the rules you need to turn into code. Then you can write the code.
The following would match a hex RGB string:
import re
_rgbstring = re.compile(r'#[a-fA-F0-9]{6}$')
def isrgbcolor(value):
return bool(_rgbstring.match(value))
This only returns True if a string starting with # followed by exactly 6 hex digits is passed in.
Demo:
>>> isrgbcolor('#FAF0E6')
True
>>> isrgbcolor('#FAF0')
False
>>> isrgbcolor('FAF0E6')
False
>>> isrgbcolor('#NotRgb')
False
If you want to support the 3-digit CSS format as well, update the pattern:
_rgbstring = re.compile(r'#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$')
This matches a hash followed by 3 hex digits, plus an optional 3 extra digits.
This seems to be the most simplest way. This regex will notice the P doesn't belong in the HEX.
import re
from pprint import pprint
hex = '#f8Ed90P'
pprint(re.findall('[^#0-9a-fA-F]', hex))
..so if there is something in the result of re.findall there's something wrong with your HEX structure.
This code resulted in:
macbook-pro:Desktop allendar$ python3 test.py
['P']
This code has the flaw that the hash-deck can be anywhere, which of course isn't right.
You might just want to check the hash-deck at the beginning of the string so the regex is easier to discern. Afterwards just only check if the other characters are conform to the characters allowed in your regex check.
Does anybody have a quickie for converting an unsafe string to an int?
The string typically comes back as: '234\r\n' or something like that.
In this case I want 234. If '-1\r\n', I want -1. I never want the method to fail but I don't want to go so far as try, except, pass just to hide errors either (in case something extreme happens).
In this case you do have a way to avoid try/except, although I wouldn't recommend it (assuming your input string is named s, and you're in a function that must return something):
xs = s.strip()
if xs[0:1] in '+-': xs = xs[1:]
if xs.isdigit(): return int(s)
else: ...
the ... part in the else is where you return whatever it is you want if, say, s was 'iamnotanumber', '23skidoo', empty, all-spaces, or the like.
Unless a lot of your input strings are non-numbers, try/except is better:
try: return int(s)
except ValueError: ...
you see the gain in conciseness, and in avoiding the fiddly string manipulation and test!-)
I see many answers do int(s.strip()), but that's supererogatory: the stripping's not needed!
>>> int(' 23 ')
23
int knows enough to ignore leading and trailing whitespace all by itself!-)
import re
int(re.sub(r'[^\d-]+', '', your_string))
This will strip everything except for numbers and the "-" sign. If you can be sure that there won't be ever any excess characters except for whitespace, use gruszczy's method instead.
int('243\r\n'.strip())
But that won't help you, if something else than a number is passed. Always put try, except and catch ValueError.
Anyway, this also works: int('243\n\r '), so maybe you don't even need strip.
EDIT:
Why don't you just write your own function, that will catch the exception and return a sane default and put into some utils module?
try:
x=int("234\r\n".strip())
except ValueError:
x=0
def str_to_int(a):
str_to_int_output=""
for i in range(len(a)):
for b in range(10):
if a[i]==str(b):
str_to_int_output+=a[i]
return int(str_to_int_output)
fn for "str to float" is a bit more comlicated, but i think i can do it if it is needed.
You could just:
def to_int(unsafe_string):
return int(unsafe_string.strip())
But it will throw a ValueError if the stripped unsafe_string is not a valid number. You can of course catch the ValueError and do what you like with it.
Without knowing what kinds of inputs you are expecting, it's hard to say what is 'enough' to solve this. If you are just worried about trailing newlines, then Xavier Combelle's or gruszczy's answer is enough:
try:
x = int(value)
except ValueError:
x = 0
If you have to find any integer, anywhere in a string, then you might need something like this:
import re
try:
x = int(re.search(r'(0|(-?[1-9][0-9]*))', searchstring).group(0))
except TypeError: # Catch exception if re.search returns None
x = 0
Under Python 3.0 (IDLE) this worked nicely
strObj = "234\r\n"
try:
#a=int(strObj)
except ValueError:
#a=-1
print(a)
>>234
If you're dealing with input you cannot trust, you never should anyway, then it's a good idea to use try, except, pass blocks to control exceptions when users provide incompatible data. It might server you better to think about try, except, pass structures as defensive measures for protecting data compatibility rather than simply hidding errors.
try:
a=int(strObj) #user sets strObj="abc"
except ValueError:
a=-1
if a != -1:
#user submitted compatible data
else:
#inform user of their error
I hope this helps.