Python: Convert a string to an integer - python

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.

Related

Time limit exceeded in valid parentheses problem

I am trying to solve the following problem in python (not for anything, just trying to learn how to code), and I keep getting the time limit exceeded error.
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
An input string is valid if:
Open brackets must be closed by the same type of brackets.
Open brackets must be closed in the correct order.
Can someone please explain why the code won't run?
Detail on my logic: I am trying to check if the input has any values (or else return true immediately), then whether it has any closed parentheses next to each other. The idea is that every true input must have either '()', '[]', or '{}' somewhere in the string. Then, I would remove those pairs until either there are no more characters, and I know it's true, or it can't find any and it is false.
If this is a poor way to think about the problem and you plan to offer a different way, please also help me understand why this code doesn't run.
class Solution:
def isValid(self, s: str) -> bool:
l = ['()','[]','{}']
while s != '':
while l[0] in s or l[1] in s or l[2] in s:
try:
s.replace(s[s.index(l[0])],'')
except:
ValueError
try:
s.replace(s[s.index(l[1])],'')
except:
ValueError
try:
s.replace(s[s.index(l[2])],'')
except:
ValueError
continue
return False
return True
s.replace(...) returns the modified string. It doesn't modify s in place; it can't, since strings are immutable.
There are other mistakes but I'll leave them as an exercise for you to figure out. Fixing this will at least get you past the infinite loop.
In addition to the above answers, it seems like you are trying to catch a ValueError when s.index() fails.
The code you have will instead catch any exception, not just ValueError.
You can do it like this:
try:
# try code
except ValueError as e:
# handle ValueError

Python KeyError and ValueError inconsistency?

I've found an inconsistency between ValueError and KeyError. The former will treat \n as a newline; the latter treats it as raw text. Is this behavior normal/expected?
TeX_dict is a dictionary to convert parts of dictionary keys to TeX formatted strings that are used when generating plots. part is one such part. Here are two examples of part:
a&b is successfully split and converted in the dictionary.
a,b&c is not.
When I raise a ValueError, the \n newline characters generate a new line. When I raise a KeyError, they do not.
geo_split = lambda thing: '\&'.join([
TeX_dict[x]
for x in thing.split('&')
])
try:
TeX = geo_split(part)
except KeyError:
msg = ("You have programmed limited functionality for "
"geometric mean keys. They can only handle species "
"that are hard coded into "
"``pccv.TeX_labels.axis_labels``.\n\n" #
"The following part failed: {}\n"
).format(part)
raise ValueError(msg) # If this is KeyError, the new lines don't print.
Here is a sample output from each:
ValueError: You have programmed limited functionality for geometric mean keys.
They can only handle species that are hard coded into
``pccv.TeX_labels.axis_labels``.
KeyError: 'You have programmed limited functionality for geometric mean keys.
They can only handle species that are hard coded into
``pccv.TeX_labels.axis_labels``.\n\nThe following part failed: a,p1&p2\n'
This is a peculiarity of the KeyError implementation.
/* If args is a tuple of exactly one item, apply repr to args[0].
This is done so that e.g. the exception raised by {}[''] prints
KeyError: ''
rather than the confusing
KeyError
alone. The downside is that if KeyError is raised with an explanatory
string, that string will be displayed in quotes. Too bad.
If args is anything else, use the default BaseException__str__().
You could work around it by passing something that overrides __repr__:
class Wrapper(str):
def __repr__(self):
return str(self)
raise KeyError(Wrapper('hello\nthere'))

What is a reliable isnumeric() function for python 3?

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"):

Check if a variable is a string of numbers like "1234"

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?

Proper Exiting of While Loop on Error

I'm curious what is the 'proper' pythonic way of handling this error with a while loop. I could simply check the string to see if it has a [-1] character beforehand in this example, but the actual code this example of my problem is based on is much more complicated.
try:
while mystring[-1] == '!' #Will throw an error if mystring is a blank string
print("Exclamation!")
mystring = mystring[:-1]
return mystring
except:
return ""
Effectively my problem is that my while loop is contingent on a check that, occasionally after some processing within the loop, will throw an error. The above is just a (perhaps overly) simplified illustration of that problem. I fixed it with a series of try: excepts:'s, but I feel like that's not the "correct" way to be addressing this issue.
Two things your current code does that you shouldn't do:
Catches any exception, you should catch just the specific exception of interest
Includes the whole loop in the try block, you should if at all possible only include that statement/expression that raises the exception
If you find yourself using while loops a lot in python, it suggests that you aren't making the most effective use of python. Given python's toolset you should almost always be using some sort of for loop. Without seeing a real sample of your code, I can't say whether that's actually true. If you want help in that area, post some code at http://codereview.stackexchange.com
A general solution to this problem is to write a function which handles the exception and use that.
def last_character(string):
try:
return string[-1]
except IndexError:
return ' '
while last_character(mystring) == '!'
mystring = mystring[:-1]
return mystring
In fact, in many cases already have exception-less equivalents to the standard constructs. This loop can easily be written using the .endswith() method. By using those or crafting your own you can deal with the exceptions most cleanly.
For your example, you could simply do something like:
while mystring and mystring[-1] == '!':
print("Exclamation!")
mystring = mystring[:-1]
return mystring
This will work because it will short-circuit and end the loop if mystring is empty, so you will never try to access the -1 index of an empty string
Edit: As Winston pointed out, you can get rid of all of the special casing by using str.endswith as in the following code
while mystring.endswith('!'):
print("Exclamation!")
mystring = mystring[:-1]
return mystring
Use mystring.rstrip('!') to remove the'!' characters at the end of the string ;-)
If the problem is much more complicated, the proper way is to catch the IndexError thrown by the operation.
try:
while mystring[-1] == '!' #Will through an error if mystring is a blank string
print("Exclamation!")
mystring = mystring[:-1]
return mystring
except IndexError:
return ""
Another way is to check the string for emptyness and avoiding using the operation which raises the exception:
while mystring and mystring[-1] == '!': # lazy boolean expression evaluation
mystring = mystring[:-1]
return mystring
Other version without the lazy boolean expression evaluation:
if not mystring:
return mystring
while mystring[-1] == '!':
mystring = mystring[:-1]
if not mystring:
break
return mystring
I personnaly favor the second version, especially if you change mystring[-1] == '!' with mystring.endswith('!') (but in that case you don't need to check for emptyness, because endswith already does this for you).

Categories