Basically, I'm asking for an input, which is going to be split(',') however, if the person doesn't input it properly, for example they accidentally input just 5, or don't include a comma at all, it comes up with an error that something is undefined.
Does anyone have any idea of how to check that the input is in the right sort of format?
Edit: Here's the code in question...it's to do with coordinates
def EnterCoords():
coordinates = input("Enter coordinates in the following format x,y").split(',')
x, y = Coordinates[0], Coordinates[1]
I then use the x and y values in a calculation elsewhere, which brings up the error IndexError: list index out of range So, if the user enters them wrong, is there a way of calling the function again, for them to try again
Given your updated question, then the best way is to use a try/except.
def enter_coords():
while True:
try:
# Use `raw_input` for Python 2.x
x, y = input('Enter coordinates ...: ').split(',')
return int(x), int(y) # maybe use `float` here?
except ValueError as e:
pass
Keep looping until a successful return. By using x, y = - you're requesting that only two values should be unpacked (less or more will raise a ValueError), if that succeeds, then you try to return the int equivalent of those values, again, if they're not suitables ints, then you get a ValueError... you then ignore that error and the loop repeats until a successful return executes.
More general approaches and the principles of using this approach are detailed in the excellent: Asking the user for input until they give a valid response
Edit: Just realized you're not looking for alpha only string.
To check for commas use any of the following:
There are multiple ways of solving this problem:
Using in operator
Check for a comma in the string using the in operator:
if "," in str:
<code on true condition>
Example:
In [8]: if "," in "Hello World!":
...: print "Contains Comma"
...:
In [9]: if "," in "Hello,World":
...: print "Contains Comma"
...:
Contains Comma
-OR-
Exception Handling
You could use try ... except block to check for error when ',' is not present in string as suggested by James Taylor.
See documentation for handling exceptions:
https://docs.python.org/2/tutorial/errors.html#handling-exceptions
-OR-
RegEx
As suggested by Malik Brahimi in the comments - "Instead of checking for a specific format, try searching for a specific values":
data = raw_input('Enter a few values: ') # let's say 1, 3, 4.5, 5,
nums = []
for entry in re.findall('[0-9.]+', data):
nums.append(float(entry))
print nums # now just numbers regardless of commas
Related
This piece of code will ask for input, compare input with content of lists and, if input and content match, return input.
If input is not in list user will be asked again for input.
def get_input(tested_list):
corect_input = False
while not corect_input:
try:
# we are comparing input to list of lists content
my_input = str.lower((input("Enter here: ")))
for line in a_list:
if my_input == line[2].lower():
return my_input
except ValueError:
print("????")
else:
corect_input = False
Now questions (I'm very beginner. Try-Except-Else is all very new for me) :
Is there any reason here to include 'except' line? Since input is converted to string, I can't see way to input anything what will cause any error.
What kind of error shall I use after 'except'.
How shall I write this piece of code to be better / cleaner/ more pythonic? :) .
thank you
First issue to note is that a_list in your function should be replaced by tested_list. a_list has not been defined and will cause an error.
There are at least 2 possible errors you can face:
AttributeError, if the 2nd index of a sublist in tested_list is not a string, e.g. if it is an integer.
IndexError, if the 2nd index of a sublist in tested_list does not exist, e.g. if the sublist is of length 2.
However, to make your try / except clause useful in this context, you need to define it within the for loop. Below is an example.
def get_input(tested_list):
correct_input = False
while not correct_input:
my_input = str.lower((input("Enter here: ")))
for line in tested_list:
try:
if my_input == line[2].lower():
return my_input
except (AttributeError, IndexError):
print("An error has occurred")
else:
correct_input = False
If I want to define a function called match_numbers, which would match the area code from one list to the phone number of another list, how should I fix my code? For example:
match_phone(['666', '332'], ['(443)241-1254', '(666)313-2534', '(332)123-3332'])
would give me
(666)313-2534
(332)123-3332
My code is:
def phone (nlist, nlist1):
results = {}
for x in nlist1:
results.setdefault(x[0:3], [])
results[x[0:3]].append(x)
for x in nlist:
if x in results:
print(results[x])
The problem with this code is, however:
It gives me the outputs in brackets, whereas I want it to print
the output line by line like shown above, and
it won't work with the parantheses in the 2nd list (for example
(666)543-2322 must be converted as 666-543-2322 for the list to
work.
Now, there are better/faster approaches to do what you are trying to do, but let us focus on fixing your code.
The first issue you have is how you are slicing your string. Remember that you start at index 0. So if you do:
x[0:3]
What you are actually getting is something like this from your string:
(12
Instead of your intended:
123
So, knowing that indexes start at 0, what you actually want to do is slice your string as such:
x[1:4]
Finally, your line here:
results[x[0:3]].append(x)
There are two problems here.
First, as mentioned above, you are still trying to slice the wrong parts of your string, so fix that.
Second, since you are trying to make a key value pair, what that above line is actually doing is making a key value pair where the value is a list. I don't think you want to do that. You want to do something like:
{'123': '(123)5556666'}
So, you don't want to use the append in this case. What you want to do is assign the string directly as the value for that key. You can do that as such:
results[x[1:4]] = x
Finally, another problem that was noticed, is in what you are doing here:
results.setdefault(x[1:4], [])
Based on the above explanation on how you want to store a string as your value in your dictionary instead of a list, so you don't need to be doing this. Therefore, you should simply be removing that line, it does not serve any purpose for what you are trying to do. You have already initialized your dictionary as results = {}
When you put it all together, your code will look like this:
def match_phone(nlist, nlist1):
results = {}
for x in nlist1:
results[x[1:4]] = x
for x in nlist:
if x in results:
print(results[x])
match_phone(['666', '332'], ['(443)241-1254', '(666)313-2534', '(332)123-3332'])
And will provide the following output:
(666)313-2534
(332)123-3332
If all the phone numbers will be in the format (ddd)ddd-dddd you can use
for number in (num for num in nlist1 if num[1:4] in nlist):
print(number)
You could use some better variable names than nlist and nlist1, in my view.
def match_phone(area_codes, numbers):
area_codes = set(area_codes)
for num in numbers:
if num in area_codes:
print num
You could do something like this:
phone_numbers = ['(443)241-1254', '(666)313-2534', '(332)123-3332']
area_codes = ['666', '332']
numbers = filter(lambda number: number[1:4] in area_codes, phone_numbers)
for number in numbers:
print(number)
Another similar way to do this without using a filter could be something like this:
for number in phone_numbers:
if number[1:4] in area_codes:
print(number)
Output in either case would be:
(666)313-2534
(332)123-3332
No one with regex solution! This may be an option too.
import re
def my_formatter(l1,l2):
mydic = {re.match(r'([(])([0-9]+)([)])([0-9]+[-][0-9]+)',i).group(2):re.match(r'([(])([0-9]+)([)])([0-9]+[-][0-9]+)',i).group(4) for i in l2}
for i in l1:
print "({0}){1}".format(str(i),str(mydic.get(i)))
my_formatter(['666', '332'], ['(443)241-1254', '(666)313-2534', '(332)123-3332'])
It prints-
(666)313-2534
(332)123-3332
Can anyone help me with the assignment - I have to reverse a string by using def. I am not allowed to use approaches like [::-1] or .reversed...
The following function works, but prints vertically:
def ex1(name):
for x in range(len(name)-1,-1,-1):
print(name[x])
k
r
o
Y
w
e
N
how do I put the letters back into horizontal order?? Anyone? Thanks!
You can use str.join and a list comprehension like so:
>>> def ex1(name):
... return "".join([name[x] for x in range(len(name)-1,-1,-1)])
...
>>> print(ex1('abcd'))
dcba
>>>
Also, notice that I made the function return the string instead of print it. If your teachers want you to use def for this job, then they probably want that too. If not, then you can always replace return with print if you want.
You were very close:
def ex1(name):
reverseName=""
for x in range(len(name)-1,-1,-1):
reverseName+=name[x]
print reverseName
The print statement prints a newline character (a line break) after each line, this is why you get your characters in vertical. The solution is not to print the character in each loop, but to collect them in a string and print the final string at once at the end.
Note that there are more efficient ways of doing this (see the other answers), but it might be the most straightforward way and the closest one to what you have already done.
Here is another way that you can reverse a string.
def ex1(name):
length = len(name)
return "".join([name[length-x-1] for x in range(0, length)])
print ex1("hello world")
name=input("Whats your name ?")
def reversemyname(name):
x=name[::-1]
return x
reversedname=reversemyname(name)
print(reversedname)
print(name[x]), # <= add that comma
if you want the output like this kroy wen then try this:
sys.stdout.write(name[x])
remember to import sys
Say I do the following:
>>> a = foo#bar.com
>>> uname, domain = a.split('#')
But what if I only ever want domain, and never uname? For example, if I only ever wanted uname and not domain, I could do this:
>>> uname, = a.split('#')
Is there a better way to split a into a tuple and have it throw away uname?
To take into account some of the other answers, you have the following options:
If you know that the string will have an '#' symbol in it then you can simply do the following:
>>> domain = a.split('#')[1]
If there is a chance that you don't have an '#' symbol, then one of the following is suggested:
>>> domain = a.partition('#')[2]
Or
try:
domain = a.split('#')[1]
except IndexError:
print "Oops! No # symbols exist!"
You could use your own coding style and specify something like "use '_' as don't care for variables whose value you want to ignore". This is a general practice in other languages like Erlang.
Then, you could just do:
uname, _ = a.split('#')
And according to the rules you set out, the value in the _ variable is to be ignored. As long as you consistently apply the rule, you should be OK.
If you know there's always an # in your string, domain = a.split('#')[1] is the way to go. Otherwise check for it first or add a try..except IndexError block aroudn it.
This gives you an empty string if there's no #:
>>> domain = a.partition('#')[2]
If you want to get the original string back when there's no #, use this:
>>> domain = a.rpartition('#')[2]
This could work:
domain = a[a.index("#") + 1:]
I have to make a rudimentary FSM in a class, and am writing it in Python. The assignment requires we read the transitions for the machine from a text file. So for example, a FSM with 3 states, each of which have 2 possible transitions, with possible inputs 'a' and 'b', wolud have a text file that looks like this:
2 # first line lists all final states
0 a 1
0 b 2
1 a 0
1 b 2
2 a 0
2 b 1
I am trying to come up with a more pythonic way to read a line at a time and convert the states to ints, while keeping the input vals as strings. Basically this is the idea:
self.finalStates = f.readline().strip("\n").split(" ")
for line in f:
current_state, input_val, next_state = [int(x) for x in line.strip("\n").split(" ")]
Of course, when it tries to int("a") it throws a ValueError. I know I could use a traditional loop and just catch the ValueError but I was hoping to have a more Pythonic way of doing this.
You should really only be trying to parse the tokens that you expect to be integers
for line in f:
tokens = line.split(" ")
current_state, input_val, next_state = int(tokens[0]), tokens[1], int(tokens[2])
Arguably more-readable:
for line in f:
current_state, input_val, next_state = parseline(line)
def parseline(line):
tokens = line.split(" ")
return (int(tokens[0]), tokens[1], int(tokens[2]))
This is something very functional, but I'm not sure if it's "pythonic"... And it may cause some people to scratch their heads. You should really have a "lazy" zip() to do it this way if you have a large number of values:
types = [int, str, int]
for line in f:
current_state, input_val, next_state = multi_type(types, line)
def multi_type(ts,xs): return [t(x) for (t,x) in zip(ts, xs.strip().split())]
Also the arguments you use for strip and split can be omitted, because the defaults will work here.
Edit: reformatted - I wouldn't use it as one long line in real code.
You got excellent answers that match your problem well. However, in other cases, there may indeed be situations where you want to convert some fields to int if feasible (i.e. if they're all digits) and leave them as str otherwise (as the title of your question suggests) without knowing in advance which fields are ints and which ones are not.
The traditional Python approach is try/except...:
def maybeint(s):
try: return int(s)
except ValueError: return s
...which you need to wrap into a function as there's no way to do a try/except in an expression (e.g. in a list comprehension). So, you'd use it like:
several_fields = [maybeint(x) for x in line.split()]
However, it is possible to do this specific task inline, if you prefer:
several_fields = [(int(x) if x.isdigit() else x) for x in line.split()]
the if/else "ternary operator" looks a bit strange, but one can get used to it;-); and the isdigit method of a string gives True if the string is nonempty and only has digits.
To repeat, this is not what you should do in your specific case, where you know the specific int-str-int pattern of input types; but it might be appropriate in a more general situation where you don't have such precise information in advance!
self.finalStates = [int(state) for state in f.readline().split()]
for line in f:
words = line.split()
current_state, input_val, next_state = int(words[0]), words[1], int(words[2])
# now do something with values
Note that you can shorten line.strip("\n").split(" ") down to just line.split(). The default behavior of str.split() is to split on any white space, and it will return a set of words that have no leading or trailing white space of any sort.
If you are converting the states to int in the loop, I presume you want the finalStates to be int as well.