I found this practice today:
Detect whether a check number is valid or not. The check number must have 10 digits, can not have 2 or more zeros followed, nor three or more digits other than zero followed
I've able to complete the first part with this code:
num_chk=input('Enter chk number: ')
if (len(num_chk) == 10):
print('valid')
else:
print('not valid')
any thoughts on how to create the logic to check if the check number has 2 consecutive 0.
thanks
You can check if the number has two or more zeroes, or three or more digits by using built-in function any(), for example:
if len(num) == 10:
if any((x in num) for x in [str(i) + str(i) + str(i) for i in range(1, 10)]):
print('invalid')
elif '00' in num:
print('invalid')
else:
print('valid')
else:
print('invalid')
any() returns True if any of the supplied expressions is True.
Let's say your check number is the variable check_number and it is 12300.
check_number = 12300
convert it to a string:
str_check_num = str(check_number)
# str_check_num now equals "12300" a a string
has_00 = "00" in str_check_num
# Returns True if "00" is in str_check_num. in this case it is.
num_chk is type str, which gives you access to:
a in b - return True if string a is in string b, e.g. '00' in num_chk
To check whether the trailing part is some number of zeroes, you can try endswith or look into regular expressions (re package in Python) if you don't know how many zeroes it might be.
A solution with regex for detecting the others condition, as suggested by #Riaz, should be definitely better than what I'm about to suggest, but for the sake of completeness, one can also do the following using itertools.groupby, grouped_L returns a list of tuples with a number followed by it's number of consecutive duplicates (Reference):
from itertools import groupby
num = 1234567890 # Using input as an int
L = [int(x) for x in str(num)]
grouped_L = [(k, sum(1 for i in g)) for k,g in groupby(L)]
validity = True
if len(str(num)) == 10:
for i in grouped_L:
if (i[0]!=0 and i[1]>2):
validity = False
break
elif (i[0]==0 and i[1]>1):
validity = False
break
else:
validity = True
else:
validity = False
if validity:
print('valid')
else:
print('not valid')
something like :
>>> def check(num):
... l=[str(i)+str(i) for i in range(10)]
... l[0]='000'
... if len(num)!=10:
... return "not valid"
... else:
... for i in l:
... if i in num:
... return "not valid"
... return "valid"
...
>>> n="1234567890"
>>> check(n)
'valid'
>>> n="1234500090"
>>> check(n)
'not valid'
If I understand the question ("two or more zeroes followed" means "two or more consecutive zeroes"?), the number must have exactly 10 digits. It must not have two (or more) consecutive zeroes. It must not have three (or more) consecutive digits other than zero. (Three consecutive zeroes implies two consecutive zeroes, so that does constitute an invalid number because of the 2nd rule--we do not need to exclude zero from the last test).
That gives that code
def validate(s):
# 10 characters
if len(s) != 10:
return False
# all digits
for c in s:
if not c.isdigit():
return False
# no two or more consecutive '0'
for a,b in zip(s[0:9],s[1:10]):
if a == b == '0':
return False
# no three or more consecutive digits
for a,b,c in zip(s[0:8],s[1:9],s[2:10]):
if (a == b == c) and a.isdigit():
return False
#
return True
TESTS = (
'12345678x0', # one character not digit
'123456789', # not 10 characters
'1234567890', # valid
'1230067890', # two consecutive zeroes
'1224567890', # valid
'1114567890', # three consecutive digits (other than zero)
)
for t in TESTS:
print( t, 'valid' if validate(t) else 'not valid' )
n = raw_input("Enter number: ")
print( n, 'valid' if validate(n) else 'not valid' )
Related
“All vanity plates must start with at least two letters.”
“… vanity plates may contain a maximum of 6 characters (letters or numbers) and a minimum of 2 characters.”
“Numbers cannot be used in the middle of a plate; they must come at the end. For example, AAA222 would be an acceptable … vanity plate; AAA22A would not be acceptable. The first number used cannot be a ‘0’.”
“No periods, spaces, or punctuation marks are allowed.”
I solved ever problem but i am having a difficult time solving the highlighted problem. AAA22A or AAA2A as invalid.
def is_valid(s):
# checks for at least 2 chars and a max of 6 characters
# and checks for at least 2 uppercase letters
if len(s) < 2 or len(s) > 6 and s[0:2].isalpha():
return False
# checks for periods, spaces, or punctuation marks
for i in s:
if i in [".", " ", "!", "?"]:
return False
# checks if numbers in string starts with 0
i = 0
while i < len(s):
if s[i].isalpha() == False:
if s[i] == "0":
return False
else:
break
i += 1
# after u see a valid number, no letter can come after it
# this is where the challenge is ,
for i in s[::-1]:
if s[i].isalpha() == True:
for j in s[::-2]:
if s[j].isalpha == False:
return False
else:
break
else:
break
# returns true if all the requirements are passed
return True
"""i tried to iterate in reverse order but that deems unsuccessful. Not sure how to solve. need help please."""
You can have a function to know if a letter comes after a number or use this piece of code directly:
def letter_after_number(s):
for i in range(len(s) - 1):
if s[i].isdigit() and s[i + 1].isalpha():
return False
return True
here the entire code:
def is_valid(s):
# checks for at least 2 chars and a max of 6 characters
# and checks for at least 2 uppercase letters
if len(s) < 2 or len(s) > 6 and s[0:2].isalpha():
return False
# checks for periods, spaces, or punctuation marks
for i in s:
if i in [".", " ", "!", "?"]:
return False
# checks if numbers in string starts with 0
i = 0
while i < len(s):
if s[i].isalpha() == False:
if s[i] == "0":
return False
else:
break
i += 1
# after u see a valid number, no letter can come after it
# this is where the challenge is ,
for i in range(len(s) - 1):
if s[i].isdigit() and s[i + 1].isalpha():
return False
# returns true if all the requirements are passed
return True
So, you don't have to go in reverse order to check if there's a letter. I would iterate over the letters until you get to a character that's a number. Once you do that, you can check that the rest of the characters are numbers.
If you did want to go in reverse, you can apply the same logic: iterate backwards, checking that you're only reading numbers. Once you hit a letter, check that the rest of the string is only letters. You can do this in multiple ways, such as using set operations or just checking the character is the correct type.
Also, note that you don't have to/shouldn't use True/False in the conditional statements. It's better to use something like if s[i].isalpha() and if not s[i].isalpha()
This could be a good use of regular expressions. This pattern only matches strings that have an optional group of letters followed by an optional group of numbers. The pattern also omits special characters by design.
import re
def is_valid(s):
if len(s) < 2 or len(s) > 6:
return False
# regular expression with two capture groups
pattern = "^([a-zA-Z]{0,6})([0-9]{0,6})$"
m = re.match(pattern, s)
if m is None:
return False
alpha = m.group(1)
numeric = m.group(2)
# first digit is not zero
if numeric[0]=="0":
return False
return True
I am making a simple program to check if a UID is valid or not:
It must contain at 2 least uppercase English alphabet characters.
It must contain at 3 least digits (0-9).
It should only contain alphanumeric characters (a-z, A-Z & 0-9).
No character should repeat.
There must be exactly 10 characters in a valid UID.
This is the code I'm using:
if __name__ == '__main__':
n = int(input())
values = [str(input()) for q in range(1,n+1)]
def checker():
cap_count = 0
num_count = 0
alnm_count = 0
for x in values[:]:
for p in x:
if p.isupper():
cap_count = cap_count+1
if cap_count > 1 and p.isnumeric():
num_count = num_count+1
if (len(x) == 10) and (x.isalnum()) and (len(x) == len(set(x))) and (cap_count > 1) and (num_count > 2):
print("Valid")
else:
print("Invalid")
checker()
Sample Input:
2
B1CD102354
B1CDEF2354
So, on giving these inputs, it works well. I have tried it up to 6-7 inputs and it works.
There is no error, it's just not giving the answer on one test case with 90 values.
Here is a link to the test that I am attempting
There's no reason that the numeric test is dependent on the uppercase test.
Change:
if cap_count > 1 and p.isnumeric():
to:
if p.isnumeric():
Also, the counters should be reset for every new value, so move the counter initialization inside the loop:
for x in values[:]:
cap_count = 0
num_count = 0
...
This seems to be the Hackerrank problem
Following code for conditions works.
def checker(uid):
if len(uid) != 10: return False
if not uid.isalnum(): return False
if len(uid) != len(set(uid)): return False
if len([c for c in uid if c.isdigit()]) < 3: return False
if len([c for c in uid if c.isupper()]) < 2: return False
return True
if __name__ == '__main__':
n = int(input())
for _ in range(n):
if checker(input()):
print("Valid")
else:
print("Invalid")
This is the offending line:
if cap_count > 1 and p.isnumeric():
which is actually adding an unwanted constraint, i.e. making digits acceptable only if at least 2 capitals were found.
By the way, this is the sort of data validation that regex is designed for, meaning that you can do all those checks in a couple of lines:
import re
pattern = r"^(?=(?:[a-z\d]*[A-Z]){2})(?=(?:\D*\d){3})(?:([a-zA-Z\d])(?!.*\1)){10}$"
regex = re.compile(pattern)
if regex.match("uid_here"):
do_something
I strongly suggest you delve into re documentation (especially the howto section) if you're willing to dissect that weird pattern and know exactly what it does.
But for the sake of summarizing a TL;DR, each element of the pattern defines a specific rule that the string must comply with to match the pattern, i.e:
^ and $ represent the ends of the string
(?=(?:[a-z\d]*[A-Z]){2}) this makes sure that at least 2 capitals are found
(?=(?:\D*\d){3}) this makes sure that at least 3 digits are found
(?:([a-zA-Z\d])(?!.*\1)){10} this makes sure that the string has exactly 10 characters with no repetition allowed
The second condition seems to accept digits only if at least two upper case letters were found before. In other words, digits appearing before the second upper case letter are not counted. It's due to the cap_count > 1 term in the condition.
In the example "123ABCDEFG" from my comment above, all digits appear before all letters, so the digit counter remains zero and the final test (num_count > 2) fails.
i am adding str[1] that is causing one repeated element to be left but if donot do that string does not get printed. any solutions
def removeCD(str):
l = len(str)
if l == 0 or l == 1:
return str
if(str[0]==str[1]):
return str[1] + removeCD(str[2:])
else:
return str[0] + removeCD(str[1:])
string = input().strip()
print(removeCD(string))
When characters are equal, you again adding duplicate character. This should work:
def removeCD(str):
l = len(str)
if l == 0 or l == 1:
return str
if(str[0]==str[1]):
return removeCD(str[1:])
else:
return str[0] + removeCD(str[1:])
string = input().strip()
print(removeCD(string))
Here is the case analysis we need to perform -
If string length is less than two (base case), there is nothing to compare, simply return the string
Otherwise (by induction) the string is at least two characters long. If the first matches the second, drop the first letter and return the recursive result
Otherwise (by induction) the string is at least two characters long and the first two characters do not match. Return the first char combined with the recursive result.
This encodes to a python program in a straightforward way -
def remove_adjacent_dupes (s = ""):
if len(s) < 2:
return s
elif s[0] == s[1]:
return remove_adjacent_dupes(s[1:])
else:
return s[0] + remove_adjacent_dupes(s[1:])
print(remove_adjacent_dupes("bookkeeper"))
# bokeper
When the characters are equal, you should be recursing on everything but the first character:
if(str[0]==str[1]):
return removeCD(str[1:])
def remove(string):
l = len(string)
if l==0 or l==1:
return string
if string[0] == string[1]:
s = remove(string[1:])
return s
else:
s = remove(string[1:])
return string[0]+s
string = input().strip()
print(remove(string))
Given below is the code to check if a list is a palindrome or not. It is giving correct output for 983. Where am I going wrong?
def palindrome(num):
flag=0
r=num[::-1]
for i in range (0, len(num)-1):
if(r[i]==num[i]):
flag=1
else:
flag=0
return flag
You should return as soon as there is a mismatch. Also, you just need to iterate till half the length:
def function(...):
...
for i in range (0, (len(num) + 1) / 2):
if r[i] != num[i]:
return False
return True
BTW, you don't need that loop. You can simply do:
def palindrome(num):
return num == num[::-1]
This would be easier:
def palindrome(num):
if num[::-1] == num:
return True
else:
return False
Your for loop checks all pairs of characters, no matter if it found mismatch or not. So, in case of string '38113' it will return True, because the flag variable will be set to True after the check for equality of last digit in '38113' and its reversed version '31183' (both equal to 3, while the string isn't a palindrome).
So, you need to return False right after you've found mismatch; if you checked all the characters and didn't find it - then return True, like so:
def palindrome(num):
r = num[::-1]
for i in range (0, len(num)-1):
if(r[i] != num[i]):
return False
return True
Also, as someone pointed out it'll be better to use python's slices - check out the documentation.
Just for the record, and for the ones looking for a more algorithmic way to validate if a given string is palindrome, two ways to achieve the same (using while and for loops):
def is_palindrome(word):
letters = list(word)
is_palindrome = True
i = 0
while len(letters) > 0 and is_palindrome:
if letters[0] != letters[-1]:
is_palindrome = False
else:
letters.pop(0)
if len(letters) > 0:
letters.pop(-1)
return is_palindrome
And....the second one:
def is_palindrome(word):
letters = list(word)
is_palindrome = True
for letter in letters:
if letter == letters[-1]:
letters.pop(-1)
else:
is_palindrome = False
break
return is_palindrome
str1=str(input('enter string:'))
save=str1
revstr=str1[::-1]
if save==revstr:
print("string is pailandrom")
else:
print("not pailadrom")
# We are taking input from the user.
# Then in the function we are reversing the input i.e a using
# slice [::-1] and
# storing in b
# It is palindrome if both a and b are same.
a = raw_input("Enter to check palindrome:")
def palin():
#Extended Slices to reverse order.
b = a[::-1]
if a == b:
print "%s is palindrome" %a
else:
print "%s is not palindrome" %a
palin()
this would be much easier:
def palindrome(num):
a=num[::-1]
if num==a:
print (num,"is palindrome")
else:
print (num,"is not palindrome")
x=input("Enter to check palindrome:")
palindrome(x)
Here in my opinion is the most elegant:
def is_palindrome(s):
if s != '':
if s[0] != s[-1]:
return False
return is_palindrome(s[1:-1])
return True
it's also the same code in the is_palindrome() function:
pip install is-palindrome
>>> from is_palindrome import is_palindrome
>>> x = "sitonapanotis"
>>> y = is_palindrome(x)
>>> y
True
Take care to note the hyphen vs underscore when installing vs. importing
a="mom"
b='mom'[::-1] # reverse the string
if a==b: # if original string equals to reversed
print ("palindrome ")
else:
print ("not a palindrome ")
def palindrome(a):
a=raw_input('Enter :')
b=a[::-1]
return a==b
I was wondering how to reverse two characters in a string.
Here are some examples:
'wing' => 'iwng', 'inwg', 'ingw'
'west' => 'ewst', 'eswt', 'estw'
I was going to use any answers given and put it in a while loop so I can get all the possible combinations of a string while swapping two characters at a time.
ex.
counter = 0
while (counter <= len(str1)):
if str1 == reverse(str2):
return str2
elif str1 == str2
return str2
else:
str1 = *some code that would swap the the characters m and n*
str1 =
n += 1
m += 1
return False
This code compares two strings, str1 to str2, and checks to see if they are the same by swapping the characters around.
ALSO, is there a way i can get this to produce a list of the results instead of printing them?
THANKS!
Try this:
s = 'wing'
s = 'west'
l = [x for x in s]
for i in xrange(len(s)-1):
l[i], l[i+1] = l[i+1], l[i]
print "".join(l)
In order to generate all possibilities, we can use:
s = "yourstring"
for i in range(0,len(s)-2):
if i>0: print s[:i]+s[i+1:i-1:-1]+s[i+2:]
else: print s[1]+s[0]+s[2:]
Since you wish to actually compare two strings to see if they "are the same by swapping two characters around," you do not actually need to generate all possible combinations, instead you can iterate through each of the characters in each of the strings and ensure that no more than two of them are not equal.
This can be done as follows:
def twoCharactersDifferent(str1,str2):
if sorted(str1) != sorted(str2): #they must contain the same letters, exactly!
return False
numDifferent = 0
for i in range(len(str1)):
numDifferent += (str1[i] != str2[i])
if numDifferent >2:
return False
return True
print twoCharactersDifferent('wings','winxg')