Upper case between a char python - python

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

Related

Chemical element symbols task

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

Problem with changing lowercase letters to uppercase and vice versa using str.replace

Ok, so this is my code, i don't want to use the built in swapcase() method. It does not work for the given string.
def myFunc(a):
for chars in range(0,len(a)):
if a[chars].islower():
a = a.replace(a[chars], a[chars].upper())
elif a[chars].isupper():
a = a.replace(a[chars], a[chars].lower())
return a
print(myFunc("AaAAaaaAAaAa"))
replace changes all the letters and you assign the values back to aso you end up with all upper cases.
def myFunc(a):
# use a list to collect changed letters
new_text = []
for char in a:
if char.islower():
new_text.append(char.upper())
else:
new_text.append(char.lower())
# join the letters back into a string
return ''.join(new_text)
print(myFunc("AaAAaaaAAaAa")) # aAaaAAAaaAaA
or shorter:
def my2ndFunc(text):
return ''.join( a.upper() if a.islower() else a.lower() for a in text)
using a list comprehension and a ternary expression to modify the letter (see Does Python have a ternary conditional operator?)
The problem was that you were doing a replace of all ocurrances of that character in the string. Here you have a working solution:
def myFunc(a):
result = ''
for chars in range(0,len(a)):
print(a[chars])
if a[chars].islower():
result += a[chars].upper()
elif a[chars].isupper():
result += a[chars].lower()
return result
print(myFunc("AaAAaaaAAaAa"))

Python 3: String validation (password)

Individually, these statements work (I've made individual helper functions) and I've compiled them onto one function. How am I able to get them to work together? Additionally, how would I make this program run without module 're'? It works but I got it off someone else on this site. These are what I need in this program:
Has to have a number
Characters in the beginning and end of the string have to be letters
Must be between 10 and 20 characters
There can't be 3 characters in a row
Previous password can't be used again
Here is my code:
import re
def password_validator (pw_v, prev_p): #pw_v = string that is to be validated; prev_p = previously used strings in a list
prev_P = [s]
# do I use 'while True' instead of returning True statements every time?
if 10 <= len(s) <=20:
return True
elif s[0] and s[-1].isalpha():
return True
elif not re.search('(.)\\1{2}', s): # How else can I write this without using 're'?
return True
elif any(digit.isdigit() for digit in s):
return True
else:
return False
Your code checks if the input satisfies only one of the conditions.
Note that when you return, the function returns and ignores the rest of the code. Considering this fact, you can use either:
(1) Nested ifs
if 10 <= len(s) <= 20:
if s[0] and s[-1].isalpha():
# the rest of the conditions
return True # all of the conditions were met
return False # one of the conditions wasn’t met
(2) Return false when one the first condition isn't met (which actually uses De Morgan's laws).
if not 10 <= len(s) <= 20:
return False
if not s[0] and s[-1].isalpha():
return False
# the rest of the conditions
Regarding the regex use, in my opinion it's elegant in this case; but you can always switch to a loop that iterates over the input's characters, combined with a counter of repeated characters (which isn't as elegant):
def three_identical_characters(input):
counter = 0
for i in range(1, len(input)):
counter += (1 if (input[i] == input[i-1]) else 0)
if counter == 2:
return True
return False
Store each of the conditions results in a variable, e.g. has_correct_length and has_digit.
Combine them:
has_correct_length = (10 <= len(s) <=20)
has_digit = any(digit.isdigit() for digit in s)
fulfills_restrictions = has_correct_length and has_digit
This way your code is much easier to read and documents itself.
You don't test if the condition is met, you test if the condition is not met:
import re
def password_validator (pw_v, prev_p): #pw_v = string that is to be validated; prev_p = previously used strings in a list
prev_P = [s]
# do I use 'while True' instead of returning True statements every time?
if not 10 <= len(s) <=20:
return False
elif not (s[0] and s[-1].isalpha()):
return False
elif re.search('(.)\\1{2}', s): # How else can I write this without using 're'?
return False
elif not any(digit.isdigit() for digit in s):
return False
else:
return True

Getting the middle character in a odd length string

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])

Search for a pattern in a string in python

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

Categories