Two try statements with the same except clause - python

Say I want to do something in python 3 with a two character string like "A1" or "1A" but first check if it's in either form beacuse the user may type it in both ways. (I already have a way to check if a char is a letter.)
How would I implement this in the shortest and easiest way?
I would like to try one thing, and if it fails, try another before raising the exception. Like so:
x = 0
string = 'A1'
try:
x = int(string[1]) # Check that second char is a digit
# something else to check first char is a letter
else try:
x = int(string[0]) # Check that first char is a digit
# something else to check second char is a letter
except:
print('Was in neither form')

You could use a loop:
for i in range(1, -1, -1):
try:
string[i] = int(string[i])
except ValueError:
pass
else:
break
else:
print('Was in neither form')
If either conversion succeeds, the loop is broken out of with break. If you didn't use break, the else suite on the for loop is executed.
However, you cannot assign to string indices as they are immutable. A better option would be to use a regular expression:
import re
valid_pattern = re.compile('^(?:\d[A-Z]|[A-Z]\d)$')
def is_valid(string):
return valid_pattern.match(string) is not None

You could create a helper to reduce the nesting:
def letter_and_digit(identifier):
a, b = identifier
try:
return a, int(b)
except ValueError:
return b, int(a)
try:
letter, digit = letter_and_digit(string)
assert letter.isupper()
except:
print('Was in neither form')
A regular expression also works, but might be overkill:
import re
LETTER_DIGIT_PAIR = re.compile('^(?=.?([A-Z]))(?=.?([0-9]))..$')
letter, digit = LETTER_DIGIT_PAIR.match('A1').groups()

For variety, this approach does not use try/except. It simply verifies that string has exactly one digit and one letter:
if not (sum(c.isdecimal() for c in string) == 1 and sum(c.isalpha() for c in string) == 1):
print('Was in neither form')

Related

Given set of numbers in a string in python

I want to check if a set of numbers is present in a string or not
Here is my code:
def check_no(string):
string = string.lower()
no = set(c)
s = set()
for i in string:
if i in no:
s.add(i)
else:
pass
if len(s) == len(no):
return("Valid")
else:
return("Not Valid")
c = input()
print(check_no(c))
if the given set of numbers is present in the string then it prints Valid and if not present it prints Not valid
the program works fine when the input is given as 123 and the string is like I have 12 car and 3 bikes then the output is valid
but when i give input as 254 and string as i hav25555number the output comes as valid but the actual output should be Not valid as 4 is not present in the string.
Can anyone help how to solve it in the provided code
I you want to check if all characters match then use all.
def check_no(text, check):
valid = all(character in text for character in check)
if valid:
return("Valid")
else:
return("Not Valid")
check = '254'
text = 'i hav25555number'
print(check_no(text, check))
The one-liner version
def check_no(text, check):
return 'Valid' if all(character in text for character in check) else 'Not Valid'
Your function is mostly correct, but probably because of your (terrible) choices of variable names, string and c variables were mixed up in the environment.
The solution is to add the parameters explicitly to the function definition (also avoid names like string or c as these could be pre-defined python keywords):
teststring = "254"
testc = "i hav25555number"
def check_no(mystring, myc):
string = mystring.lower()
no = set(c)
print("string is",string)
s = set()
for i in string:
if str(i) in no:
# print(i, " in ", no)
s.add(i)
else:
pass
# print("s is",s)
# print("no is",no)
if len(s) == len(no):
return("Valid")
else:
return("Not Valid")
print(check_no(teststring,testc))
gives:
print(check_no(teststring,testc))
string is 254
Not Valid
As mentioned before, you can use all to make your code more elegant, although there is nothing wrong with your implementation either.

How to make my output return True if a certain criteria is met?

So I wrote this code to find whether there is an uppercase letter AND a number in my string or not and here is what I have so far
def passwordOK(password: str):
for char in password:
if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and "1234567890":
return True
else:
return False
print(passwordOK(password='roskaisHsodihf'))
but the result only retyrns if the first variable is modified, so the output only prints True if the first variable is a number or an uppercase letter
What changes to my code should be made?
Please do not use import and try to use the least amount of built in functions possible
def passwordOK(txt):
return True if any(t.isupper() for t in txt) and any(t.isdigit() for t in txt) else False
3 issues:
You always return from the first loop iteration
if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and "1234567890" does not mean what you think it does.
If it did, your logic would still be wrong. A char cannot be an uppercase letter AND a digit at the same time. And if you mean or, one of the two still does not confirm the existence of the other in another position.
The logic you need should go along the following lines:
def passwordOK(password: str):
upper = digit = False
for char in password:
if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and "1234567890":
upper = True
if char in "1234567890":
digit = True
if upper and digit:
return True
return False
If you were to use some utils you could avoid some of the boilerplate code:
from string import ascii_uppercase, digits
def passwordOK(password: str):
upper = any(c in ascii_uppercase for c in password)
digit = any(c in digits for c in password)
return upper and digit
Or even shorter, using the test methods:
def passwordOK(password: str):
return any(map(str.isupper, password)) and any(map(str.isdigit, password))
Logical comparisons do not work like you expect them judging by your code. Each part left and right to the and keyword will return either True or False. Therefore you need to repeat the char variable to check against your second list of characters like so:
if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and char in "1234567890":
An non-empty string will return True by default in such a scenario.
Edit:
Also you have to use or because and will only return True if both creterias are met. A single char can't be in two disjunct sets at the same time.
An approach here would be to set a variable if either criteria is met and as soon as both ciriterias are met, you return True.

How do I use for loops with functions for string input in python?

I'm having trouble with creating a function that takes an argument of a string and returns just the numbers in type str. My code looks something like this.:
def check_if_number(number_string):
for ch in number_string:
if ch.isdigit():
num = number_string[ch]
return num
print(check_if_number('1655t'), end='')
It should print: 1655
You should add each char to a string if it is a digit :
def check_if_number(number_string):
digit_string = ""
for ch in number_string:
if ch.isdigit():
digit_string += ch
return digit_string
print(check_if_number('1655t'))
# 1655
Note that you can also use the re library :
import re
re.sub("\D", "", "1655t")
#1655
This code replace every non-digit character (matched by \D) by an empty string.
Have a look at this question to find more way to do it
You can do this :
def check_if_number(number_string):
num = ""
for ix in number_string :
if ix.isdigit():
num += ix
return int(num)
This function will return 1655, if the input is 1655t. You return from the function once you scan the complete string and append all ints to a string.
The easy way would be just using filter and concatenating the filtered letters in the end:
def check_if_number(number_string):
return ''.join(filter(str.isdigit, number_string))
Assuming all numbers are together (i.e. No letters exist between digits like "1e234g7"),
def check_if_number(number_string):
num = ''
for ch in number_string:
if ch.isdigit():
num += ch
return num
print(check_if_number('1655t'), end='')
This will return a string that only has digits in it. If you want to return a type int, then simply do return int(num).
If you want to take floats into account as well:
def check_if_number(number_string):
num = ''
for ch in number_string:
if ch == '.' or ch.isdigit():
num += ch
return num
print(check_if_number('1655t'), end='')
Similarly, this will return a string. If you want type float, simply do return float(num).
I tried not to deviate too much from what you already had... I hope this helps.
I'm uncertain what check_leap_year() function is so I just commented it out and called the function you gave us instead.
When you pass anything into a function in order to manipulate it and spit it back out different than it came in you should create a new variable for the changed data set.
In this case I used num = ""
By initiating an empty string inside of the function I can now add the data that pass my condition to that new, empty string.
isdigit() returns a boolean. So instead of using if x.isdigit: get in the habit of checking the boolean. Try if x.isdigit() is True instead.
Return your finished new string AFTER it is finished. Make sure your return statement is indented correctly or you are only going to return one number instead of all of them. The return should be outside of the loop so that it will only return once the loop is done.
num_string = "1a2s3d4f5g666hhh777jjj888kkk9l0"
def check_if_number(number_string):
num = ""
for ch in number_string:
if ch.isdigit() is True:
num += ch
return num
print(check_if_number(num_string))
Output:
>>> 1234566677788890

Check python function determine isogram from codewars

An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.
is_isogram("Dermatoglyphics" ) == true
is_isogram("aba" ) == false
is_isogram("moOse" ) == false # -- ignore letter case
Here is my code:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
else:
return True
And when I tried to run the test code Test.assert_equals(is_isogram("moOse"), False, "same chars may not be same case" ) It failed, but I thought I did convert everything into lowercase. Can someone help?
Try this:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
return True
In your code when is_isogram("moose") is called, it will see that the first character's ('m') count is not greater than 1. So it will return True. Once it hits the return statement, it will stop the execution for the rest string. So you should really write return True only after for-loop to make sure that the function checks for the whole string.
If however, at any point, it finds a character's count to be greater than 1, then it will simply return False and stop executing because there's no point of checking any more when one point is found where condition does not hold.
How about using sets? Casting the string into a set will drop the duplicate characters, causing isograms to return as True, as the length of the set won't differ from the length of the original string:
def is_isogram(s):
s = s.lower()
return len(set(s)) == len(s)
print is_isogram("Dermatoglyphics")
print is_isogram("aba")
print is_isogram("moOse")
print is_isogram("")
This outputs:
True
False
False
True
Try this :
def is_isogram(s):
string = s.lower()
if len(s) == len(set(string)):
return True
return False
Try this out:
def is_isogram(string):
return len(string) == len(set(string.lower()))
"Implement a function that determines whether a string that contains only letters is an isogram."
By using sets, you can create unique elements. So if there are any repeating numbers, it will only select one. By calling len() on these strings, you can compare the length to the original.
Sorry if I explained it poorly. I am working on this.
let us define an isogram well:
according to wikipedia An Isogram is a word in which no letter occurs more than once.
check here for more about an isogram
just remind letter
I write this code and it works for me :
def is_isogram(argument):
print(len(argument))
if isinstance(argument,str):
valeur=argument.lower()
if not argument:
return False
else:
for char in valeur:
if valeur.count(char)>1 or not char.isalpha():
return False
return True
else:
raise TypeError("need a string ")
NB: the hidden test is the fact that you must check if the char in the string is a alpha character a-z, when i add this it pass all the hiddens tests
up vote if this help
I reckon this might not be the best solution in terms of maximizing memory space and time. This answer is just for intuition purposes using a dictionary and two for loops:
def is_isogram(string):
#your code here
#create an empty dictionary
m={}
#loop through the string and check for repeating characters
for char in string:
#make all characters lower case to ignore case variations
char = char.lower()
if char in m:
m[char] += 1
else:
m[char] = 1
#loop through dictionary and get value counts.
for j, v in m.items():
#if there is a letter/character with a count > 1 return False
if v > 1:
return False
#Notice the scope of the "return True" command. It is outside.
return True

Python empty string index error

How do I stop the index error that occurs whenever I input an empty string?
s = input("Enter a phrase: ")
if s[0] in ["a","e","i","o","u","A","E","I","O","U"]:
print("an", s)
else:
print("a", s)
You can use the str.startswith() method to test if a string starts with a specific character; the method takes either a single string, or a tuple of strings:
if s.lower().startswith(tuple('aeiou')):
The str.startswith() method doesn't care if s is empty:
>>> s = ''
>>> s.startswith('a')
False
By using str.lower() you can save yourself from having to type out all vowels in both lower and upper case; you can just store vowels into a separate variable to reuse the same tuple everywhere you need it:
vowels = tuple('aeiou')
if s.lower().startswith(vowels):
In that case I'd just include the uppercase characters; you only need to type it out once, after all:
vowels = tuple('aeiouAEIOU')
if s.startswith(vowels):
This will check the boolean value of s first, and only if it's True it will try to get the first character. Since a empty string is boolean False it will never go there unless you have at least a one-character string.
if s and s[0] in ["a","e","i","o","u","A","E","I","O","U"]:
print("an", s)
General solution using try/except:
s = input("Enter a phrase: ")
try:
if s[0].lower() in "aeiou":
print("an", s)
else:
print("a", s)
except IndexError:
# stuff you want to do if string is empty
Another approach:
s = ""
while len(s) == 0:
s = input("Enter a phrase: ")
if s[0].lower() in "aeiou":
print("an", s)
else:
print("a", s)
Even shorter:if s[0:][0] in vowels: but of course this not pass as 'pythonic' I guess. What it does: a slice (variable[from:to]) may be empty without causing an error. We just have to make sure that only the first element is returned in case the input is longer than 1 character.
Edit: no, sorry, this will not work if s=''. You have to use 'if s[0:][0:] in vowels:' but this clearly crosses a line now. Ugly.
Just use
if s:
if s[0] in vowels:
as suggested before.

Categories