I have to make a task where we need to check if a symbol is a valid symbol (by the rules of the task)
The background information of the task which I probably won't be able to explain:
Example provided by the assignment:
def isvalid(symbol, element, length = None):
elbool = False
if symbol[0]!=symbol[0].upper():
return False #first letter in the symbol has to be a capital letter
for i in range(len(symbol)-1):
if element.find(symbol[i+1])>element.find(symbol[i]): #checking if the order is correct
elbool = True
else:
return False
if length is not None:
if len(symbol)!=length:
return False
else:
elbool = True
return elbool
Is my code now but it doesn't work for example with this one: isvalid('Rcm', 'Americium') because there is an m before the c and it counts that one.
So I think I need to split the element string from the last letter in the symbol so I don't have that problem but how do I do that?
Sorry if the question is a bit confusing.
You need to use .find(needle, start_pos) to look for the character after a certain location in element. Also, you don't need to mess with indices and keep finding the previous and current character from symbol. Just keep track of the location of the current character for the next iteration.
You should also do a case-insensitive search, because, using your example, there is no "R" in "Americium". I do this by converting element to lowercase once, and then doing .find(c.lower(), ...) on each character in symbol
Finally, you forgot to check that all characters other than the first one in symbol are lowercase. I also added that to the for loop.
element = element.lower() # Lowercase element so that we can find characters correctly
lastfound = 0
for ix, c in enumerate(symbol):
if ix > 0 and c.isupper():
# Not the first character, and is uppercase
return False
thisfound = element.find(c.lower(), lastfound) # Find the location of this character
if thisfound == -1: # character not found in element after location lastfound
return False
lastfound = thisfound # Set lastfound for the next iteration
A few other minor suggestions:
You can return False as soon as you find something wrong. Then, at the end of the function, just return True because the only way you reach the end is when nothing is wrong.
You can check if a character is lowercase with symbol[0].islower(). No need to do symbol[0] != symbol[0].upper().
You should check for the length requirement before you check for the order of characters, because that's the simpler check.
Applying all these:
def isvalid(symbol, element, length = None):
if symbol[0].islower():
return False
if length is not None and len(symbol) != length:
return False
element = element.lower() # Lowercase element so that we can find characters correctly
lastfound = 0
for ix, c in enumerate(symbol):
if ix > 0 and c.isupper():
return False
thisfound = element.find(c.lower(), lastfound) # Find the location of this character
if thisfound == -1: # character not found in element after location lastfound
return False
lastfound = thisfound # Set lastfound for the next iteration
return True
Using your tests:
>> isvalid('Zer', 'Zeddemorium')
True
>> isvalid('Zer', 'Zeddemorium', 2)
False
>> isvalid('di', 'Zeddemorium')
False
>> isvalid('Rcm', 'Americium')
True
Related
Given a string s, return true if the s can be palindrome after deleting at most one character from it.
Example 1:
Input: s = "aba"
Output: true
Example 2:
Input: s = "abca"
Output: true
Explanation: You could delete the character 'c'.
Example 3:
Input: s = "abc"
Output: false
For this problem in leetcode my code has passed 462/469 test cases:
Following is the test case for which my code is failing the test.
"aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga"
My code is:
class Solution:
def validPalindrome(self, s: str) -> bool:
skip=0
l,r=0,len(s)-1
while l<r:
if s[l]==s[r]:
l+=1
r-=1
elif s[l]!=s[r] and skip<1 and s[l+1]==s[r]:
l+=1
skip=1
elif s[l]!=s[r] and skip<1 and s[r-1]==s[l]:
r-=1
skip=1
else:
return False
return True
What is the problem with my code?
Note: in this string the output should be true, mine returns false
From left there are characters 'lcup' and from right there are characters 'lucup'
My code is supposed to skip the letter u from right side and continue.
"aguokepatgbnvfqmgm**lcup**uufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuu**pucul**mgmqfvnbgtapekouga"
Another example: It returns true for the following string:
s='adau'
Skips letter 'u' as expected.
However when I use the example according to the test case string that failed, it returns False. s= 'cuppucu'
It should skip first u from the right side and return True but it doesn't.
However as soon as I replace that last letter 'u' with letter 'a' it skips the letter 'a' and returns True. What's the problem here?
I over-complicated this in my first answer. I thought that you had to skip a particular character multiple times. As others have pointed out, that isn't true. So you have a solution from someone else, but you wanted to know how to change your code to always do the right thing. One way would be to run your algorithm twice. The first time, you only consider if you can skip a character on the left side of the input string as you're walking over it. For the second call, you only consider skipping a character on the right side. For cases like the one you ran into here where you could choose to skip either character, but only one will produce a positive result, well then if you try both cases, one or the other will always succeed when it should.
So here's that simple change you can make...modifying your function only slightly, and then calling it twice.
class Solution:
def _validPalindrome(self, s: str, choose_first: bool) -> bool:
skip = 0
l, r = 0, len(s) - 1
while l < r:
if s[l] == s[r]:
l += 1
r -= 1
elif choose_first and s[l] != s[r] and skip < 1 and s[r - 1] == s[l]:
r -= 1
skip = 1
elif not choose_first and s[l] != s[r] and skip < 1 and s[l + 1] == s[r]:
l += 1
skip = 1
else:
return False
return True
def validPalindrome(self, s: str) -> bool:
return self._validPalindrome(s, False) or self._validPalindrome(s, True)
def main():
inp = "aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga"
print(Solution().validPalindrome(inp))
main()
Result:
True
This should pass for all the cases for which your original code passed.
Imagine the string 'abbab'. First you check index 0 and 4 with the values "a" and "b". They are not the same, but the "b" at index 1 matches the "b" at index 4. So you move forward to 1 and 4. Next is 2 and 3 and those are "b" and "a" and those don't match too. End of the story.
abbab
l r
abbab
l r
abbab
lr
-> False
Now let's switch around the elif blocks. Again you check index 0 and 4 first. They are not the same, so you now change the right index first and see that 0 and 3 are both "a". The next comparison is at indexes 1 and 2 with "b". Finished. Found a match.
abbab
l r
abbab
l r
abbab
lr
-> True
You didn't ask for it but here is a working solution with a different approach.
class Solution:
def generate_strings(self, s):
yield s, s[::-1]
for pos in range(len(s)):
t = ''.join(c for i, c in enumerate(s) if i != pos)
yield t, t[::-1]
def validPalindrome(self, p):
return any(x == y for x, y in self.generate_strings(p))
I am trying to make function, that returns True when value of hcl is correct with required specification (it's inside multi-line comment in the function). The first thing I wanted to check was if length of that value is correct (should be # + 6 other chars), and when that would be correct I would check if all chars are in group of a-f or 0-9 - and that was my idea to solve this problem, but unfortunately there is a
ValueError: substring not found
(when second elem of list goes to the function), that I don't understand(btw. as always, you have some reasoning, and when it there is a mistake you can't found it, because for you everything is working and this 'should work').
def check_hcl(line):
'''
a # followed by exactly six characters 0-9 or a-f.
'''
print(line[line.index(':')+1], len(line[line.index(':')+2:]))
if line[line.index(':')+1] != '#' or len(line[line.index(':')+2:]) != 6:
return False
else:
return True
list = ['hcl:#866857','#52a9af','#cfa07d','7d3b0c','#cc0362','#a9784']
#false #false
for i in list:
print(check_hcl(i))
You can use the match() method from the built-in re module:
import re
def check_hcl(line):
if re.match("(.*?)#[a-f0-9]{6}", line):
return True
return False
list = ['hcl:#866857','#52a9af','#cfa07d','7d3b0c','#cc0362','#a9784']
for i in list:
print(check_hcl(i))
Output:
True
True
True
False
True
False
Explanation:
The pattern (.*?)#[a-f0-9]{6} can be broken down to 3 parts:
(.*?) matches anything of any length, including substrings of length 0.
# matches a '#'.
[a-f0-9]{6} matches a substring of characters a to f and numbers 0 to 9 of length 6.
Credits to #Ian.
def get_middle_character(odd_string):
variable = len(odd_string)
x = str((variable/2))
middle_character = odd_string.find(x)
middle_character2 = odd_string[middle_character]
return middle_character2
def main():
print('Enter a odd length string: ')
odd_string = input()
print('The middle character is', get_middle_character(odd_string))
main()
I need to figure out how to print the middle character in a given odd length string. But when I run this code, I only get the last character. What is the problem?
You need to think more carefully about what your code is actually doing. Let's do this with an example:
def get_middle_character(odd_string):
Let's say that we call get_middle_character('hello'), so odd_string is 'hello':
variable = len(odd_string) # variable = 5
Everything is OK so far.
x = str((variable/2)) # x = '2'
This is the first thing that is obviously odd - why do you want the string '2'? That's the index of the middle character, don't you just want an integer? Also you only need one pair of parentheses there, the other set is redundant.
middle_character = odd_string.find(x) # middle_character = -1
Obviously you can't str.find the substring '2' in odd_string, because it was never there. str.find returns -1 if it cannot find the substring; you should use str.index instead, which gives you a nice clear ValueError when it can't find the substring.
Note that even if you were searching for the middle character, rather than the stringified index of the middle character, you would get into trouble as str.find gives the first index at which the substring appears, which may not be the one you're after (consider 'lolly'.find('l')...).
middle_character2 = odd_string[middle_character] # middle_character2 = 'o'
As Python allows negative indexing from the end of a sequence, -1 is the index of the last character.
return middle_character2 # return 'o'
You could actually have simplified to return odd_string[middle_character], and removed the superfluous assignment; you'd have still had the wrong answer, but from neater code (and without middle_character2, which is a terrible name).
Hopefully you can now see where you went wrong, and it's trivially obvious what you should do to fix it. Next time use e.g. Python Tutor to debug your code before asking a question here.
You need to simply access character based on index of string and string slicing. For example:
>>> s = '1234567'
>>> middle_index = len(s)/2
>>> first_half, middle, second_half = s[:middle_index], s[middle_index], s[middle_index+1:]
>>> first_half, middle, second_half
('123', '4', '567')
Explanation:
str[:n]: returns string from 0th index to n-1th index
str[n]: returns value at nth index
str[n:]: returns value from nth index till end of list
Should be like below:
def get_middle_character(odd_string):
variable = len(odd_string)/2
middle_character = odd_string[variable +1]
return middle_character
i know its too late but i post my solution
I hope it will be useful ;)
def get_middle_char(string):
if len(string) % 2 == 0:
return None
elif len(string) <= 1:
return None
str_len = int(len(string)/2))
return string[strlen]
reversedString = ''
print('What is your name')
str = input()
idx = len(str)
print(idx)
str_to_iterate = str
for char in str_to_iterate[::-1]:
print(char)
evenodd = len(str) % 2
if evenodd == 0:
print('even')
else:
print('odd')
l = str
if len(l) % 2 == 0:
x = len(l) // 2
y = len(l) // 2 - 1
print(l[x], l[y])
else:
n = len(l) // 2
print(l[n])
I need help how do I get upper case between two stars like this.
INPUT: "S*t*a*r*s are every*where*"
OUTPUT: "STaRs are everyWHERE"
My code is here:
def trans(s):
x = ""
a = False
for j in range(len(s)):
if s[j] == "*" or a:
a = True
if a:
x += s[j].upper()
else:
x += s[j]
return "".join(x.replace("*",""))
The problem is I don't know where in loop set back to False. Now it just sees * and makes everything uppercase.
Note: The other answers does a fine job of showing you how to fix your code. Here's another way to do it, which you may find easier once you learn regular expressions.
You could use re.sub function.
>>> s = "S*t*a*r*s are every*where*"
>>> re.sub(r'\*([^*]*)\*', lambda m: m.group(1).upper(), s)
'STaRs are everyWHERE'
In regex * is a special meta character which repeats the previous token zero or more times. In-order to match a literal *, you need to use \* in the regex.
So \*([^*]*)\* regex matches every pair of * blocks ie (*t*, *r*, *where*) and the in-between characters (chars present inside the * block) are captured by the group 1.
For every match, re.sub function would replace the matched *..* block with string-inside-*.upper() . ie, it would apply the upper() function on the strings present inside the * and return the result as replacement string.
You need to toggle your state; each time you find a * you invert the state of your function so that you can switch between uppercasing and lowercasing as you traverse the text.
You can most easily do this with not; not a would return True if it was False and vice-versa:
def trans(s):
x = ""
a = False
for j in range(len(s)):
if s[j] == "*":
a = not a # change state; false to true and true to false
continue # no need to add the star to the output
if a:
x += s[j].upper()
else:
x += s[j]
return x
Each time you find a * character, a is toggled; by using continue at that time you also prevent the * character being added to the output, so the replace() can be avoided altogether. The ''.join() call on a string produces just the same string again, it is not needed in this case.
You don't need a range() here, you could just loop over s directly. You could use better names too:
def trans(string):
result = ""
do_upper = False
for character in string:
if character == "*":
do_upper = not do_upper # change state; false to true and true to false
continue # no need to add the star to the output
result += character.upper() if do_upper else character
return result
Demo:
>>> def trans(string):
... result = ""
... do_upper = False
... for character in string:
... if character == "*":
... do_upper = not do_upper # change state; false to true and true to false
... continue # no need to add the star to the output
... result += character.upper() if do_upper else character
... return result
...
>>> trans('S*t*a*r*s are every*where*')
'STaRs are everyWHERE'
Think of it like this. Whenever you see a *, you need to alternate between upper and original cases. So, implement the same in the code, like this
def trans(s):
x, flag = "", False
# You can iterate the string object with `for`
for char in s:
# The current character is a `*`
if char == "*":
# flip the flag everytime you see a `*`.
flag = not flag
# Skip further processing, as the current character is `*`
continue
if flag:
# If the flag is Truthy, we need to uppercase the string
x += char.upper()
else:
# Otherwise add the character as it is to the result.
x += char
# no need to `join` and `replace`, as we already skipped `*`. So just return.
return x
a should toggle between True and False. You only set it to True. Also iterate directly over the characters of the string instead over a index. And use more comprehensive variable names. The join is unnecessary and the replace is not needed, if you skip the '*' at once:
def trans(text):
result = ""
upper = False
for char in text:
if char == "*":
upper = not upper
elif upper:
result += char.upper()
else:
result += char
return result
Question: I am very new to python so please bear with me. This is a homework assignment that I need some help with.
So, for the matchPat function, I need to write a function that will take two arguments, str1 and str2, and return a Boolean indicating whether str1 is in str2. But I have to use an asterisk as a wild card in str1. The * can only be used in str1 and it will represent one or more characters that I need to ignore. Examples of matchPat are as follow:
matchPat ( 'a*t*r', 'anteaters' ) : True
matchPat ( 'a*t*r', 'albatross' ) : True
matchPat ( 'a*t*r', 'artist' ) : False
My current matchPat function can tell whether the characters of str1 are in str2 but I don't really know how I could tell python (by using the * as a wild card) to look for 'a' (the first letter) and after it finds a, skip the next 0 or more characters until it finds the next letter(which would be 't' in the example) and so on.
def matchPat(str1,str2):
## str(*)==str(=>1)
if str1=='':
return True
elif str2=='':
return False
elif str1[0]==str2[0]:
return matchPat(str1[2],str2[len(str1)-1])
else: return True
Python strings have the in operator; you can check if str1 is a substring of str2 using str1 in str2.
You can split a string into a list of substrings based on a token. "a*b*c".split("*") is ["a","b","c"].
You can find the offset of next occurrence of a substring in a string using the string's find method.
So the problem of wildcard matching becomes:
split the pattern into parts which were separated by astrix
for each part of the pattern
can we find this after the previous part's locations?
You are going to have to cope with corner cases like patterns that start with or end with an asterisk or have two asterisk beside each other and so on. Good luck!
There is a find() method of strings that searches for a substring from a particular point, returning either its index (if found) or -1 if not found. The index() method is similar but raises an exception if the target string is not found.
I'd suggest that you first split the pattern string on "*". This will give you a list of chunks to look for. Set the starting position to zero, and for each element in the list of chunks, do a find() or index() from the current position.
If you find the current chunk then work out from its starting position and length where to start searching for the next chunk and update the starting position. If you find all the chunks then the target string matches the pattern. If any chunk is missing then the pattern search should fail.
Since this is homework I am hoping that gives you enough of an idea to move on.
The basic idea here is to compare each character in str1 and str2, and if char in str1 is "*", find that character in str2 which is the character next to the "*" in str1.
Assuming that you are not going to use any function, (except find(), which can be implemented easily), this is the hard way (the code is straight-forward but messy, and I've commented wherever possible)-
def matchPat(str1, str2):
index1 = 0
index2 = 0
while index1 < len(str1):
c = str1[index1]
#Check if the str2 has run it's course.
if index2 >= len(str2):
#This needs to be checked,assuming matchPatch("*", "") to be true
if(len(str2) == 0 and str1 == "*"):
return True
return False
#If c is not "*", then it's normal comparision.
if c != "*":
if c != str2[index2]:
return False
index2 += 1
#If c is "*", then you need to increment str1,
#search for the next value in str2,
#and update index2
else:
index1 += 1
if(index1 == len(str1)):
return True
c = str1[index1]
#Search the character in str2
i = str2.find(c, index2)
#If search fails, return False
if(i == -1):
return False
index2 = i + 1
index1 += 1
return True
OUTPUT -
print matchPat("abcde", "abcd")
#False
print matchPat("a", "")
#False
print matchPat("", "a")
#True
print matchPat("", "")
#True
print matchPat("abc", "abc")
#True
print matchPat("ab*cd", "abacacd")
#False
print matchPat("ab*cd", "abaascd")
#True
print matchPat ('a*t*r', 'anteater')
#True
print matchPat ('a*t*r', 'albatross')
#True
print matchPat ('a*t*r', 'artist')
#False
Without giving you the complete answer, first, split the str1 string into a list of strings on the '*' character. I usually call str1 the "needle" and str2 the "haystack", since you are looking for the needle in the haystack.
needles = needle.split('*')
Next, have a counter (which I will call i) start at 0. You will always be looking at haystack[i:] for the next string in needles.
In pseudocode, it'll look like this:
needles = needle.split('*')
i = 0
loop through all strings in needles:
if current needle not in haystack[i:], return false
increment i to just after the occurence of the current needle in haystack (use the find() string method or write your own function to handle this)
return true
Are you allowed to use regular expressions? If so, the function you're looking for already exists in the re.search function:
import re
bool(re.search('a.t.r', 'anteasters')) # True
bool(re.search('a.t.r', 'artist' )) # False
And if asterisks are a strict necessity, you can use regular expressions for that, too:
newstr = re.sub('\*', '.', 'a*t*r') # Replace * with .
bool(re.search(newstr, 'anteasters')) # Search using the new string
If regular expressions aren't allowed, the simplest way to do that would be to look at substrings of the second string that are the same length as the first string, and compare the two. Something like this:
def matchpat(str1, str2):
if len(str1) > len(str2): return False #Can't match if the first string is longer
for i in range(0, len(str2)-len(str1)+1):
substring = str2[i:i+len(str1)] # create substring of same length as first string
for j in range(0, len(str1)):
matched = False # assume False until match is found
if str1[j] != '*' and str1[j] != substring[j]: # check each character
break
matched = True
if matched == True: break # we don't need to keep searching if we've found a match
return matched