Function to count small and Capital letters in a string - python

I wrote a function which takes a string and gives back the count of small letters and the count of capital letters in that string. The program works for single word but as soon I add two words containing 'space' in between two words, messes things up. spaces counts too.
What is your thoughts?
def myfunc(s):
s = str(s)
upperl = 0
lowerl = 0
for i in s:
if i == i.lower():
lowerl += 1
if i == i.upper():
upperl += 1
if i == ' ':
continue
return upperl,lowerl
x = myfunc('hello G')
print (x)
from the word 'hello G' we expect upper letter and lower letter
count as 1,5 but that space between two words makes it 2,6.

The problem is that ' ' == ' '.upper() and ' ' == ' '.lower() are both true, and you're not checking whether you're currently dealing with an alphanumeric character or something else. Instead, you can check whether you're working with a lowercase letter or an uppercase letter.
Try this:
def calculate_case_count(string: str):
string = str(string)
upper_letter_count = 0
lower_letter_count = 0
for letter in string:
if letter.islower():
lower_letter_count += 1
elif letter.isupper():
upper_letter_count += 1
return upper_letter_count, lower_letter_count
result = calculate_case_count('hello G ')
print(result) # (1, 5)

Using regex will be cleaner solution here
import re
def count_letter_cases(text):
n_lower = len(re.findall("[a-z]", text))
n_upper = len(re.findall("[A-Z]", text))
return n_lower, n_upper
print(count_letter_cases("Hello Goat"))
## Result: (7,2)

from collections import Counter
def count_cases(strng):
counts = Counter(strng)
upper = 0
lower = 0
for char, count in counts.items():
if char.isupper():
upper += count
elif char.islower():
lower += count
return (upper, lower)
Edit: Removed string module. Using internal islower and isupper methods.

Related

how replace every successive character in string with ‘#’ with python?

Example- For Given string ‘Hello World’ returned string is ‘H#l#o W#r#d’.
i tried this code but spaces are also included in this . i want spaces to be maintain in between words
def changer():
ch=[]
for i in 'Hello World':
ch.append(i)
for j in range(1,len(ch),2):
ch[j]= '#'
s=''
for k in ch:
s=s+k
print(s)
changer()
Output - H#l#o#W#r#d
Output i want = H#l#o W#r#d
You can str.split on whitespace to get substrings, then for each substring replace all the odd characters with '#' while preserving the even characters. Then str.join the replaced substrings back together.
>>> ' '.join(''.join('#' if v%2 else j for v,j in enumerate(i)) for i in s.split())
'H#l#o W#r#d'
you can control the increment, by default 2 but, in case of spaces 1 to jump it and continue evaluating the next word
def changer():
ch=[]
increment = 2
for i in 'Hello World':
ch.append(i)
for j in range(1,len(ch),increment):
if not ch[j].isspace():
ch[j]= '#'
increment = 2
else:
increment = 1
s=''
for k in ch:
s=s+k
print(s)
changer()
Since you said you don't want spaces to be included in the output, don't include them:
ch=[]
for i in 'Hello World':
ch.append(i)
for j in range(1,len(ch),2):
if ch[j] != " ": # don't 'include' spaces
ch[j]= '#'
s=''
for k in ch:
s=s+k
print(s)
There are a lot of very inconsistent answers here. I think we need a little more info to get you the solution you are expecting. Can you give a string with more words in it to confirm your desired output. You said you want every successive character to be a #, and gave an example of H#l#o W#r#d. Do you want the space to be included in determining what the next character should be? Or should the space be written, but skipped over as a determining factor for the next character? The other option would be 'H#l#o #o#l#' where the space is included in the new text, but is ignored when determining the next character.
Some of the answers give something like this:
string = "Hello World This Is A Test"
'H#l#o W#r#d T#i# I# A T#s#'
'H#l#o W#r#d T#i# #s A T#s#'
'H#l#o W#r#d T#i# I# A T#s# '
This code gives the output: 'H#l#o W#r#d T#i# #s A T#s#'
string = 'Hello World This Is A Test'
solution = ''
c = 0
for letter in string:
if letter == ' ':
solution += ' '
c += 1
elif c % 2:
solution += "#"
c += 1
else:
solution += letter
c += 1
If you actually want the desired outcome if including the whitespace, but not having them be a factor in determing the next character, alls you need to do is remove the counter first check so the spaces do not affect the succession. The solution would be: 'H#l#o #o#l# T#i# I# A #e#t'
You could use accumulate from itertools to build the resulting string progressively
from itertools import accumulate
s = "Hello World"
p = "".join(accumulate(s,lambda r,c:c if {r[-1],c}&set(" #") else "#"))
print(p)
Using your algorithm, you can process each word individually, this way you don't run into issues with spaces. Here's an adaptation of your algorithm where each word is concatenated to a string after being processed:
my_string = 'Hello World'
my_processed_string = ''
for word in my_string.split(' '):
ch = []
for i in word:
ch.append(i)
for j in range(1, len(ch), 2):
ch[j] = '#'
for k in ch:
my_processed_string += k
my_processed_string += ' '
You can maintain a count separate of whitespace and check its lowest bit, replacing the character with hash depending on even or odd.
def changer():
ch=[]
count = 0 # hash even vals (skips 0 because count advanced before compare)
for c in 'Hello World':
if c.isspace():
count = 0 # restart count
else:
count += 1
if not count & 1:
c = '#'
ch.append(c)
s = ''.join(ch)
print(s)
changer()
Result
H#l#o W#r#d
I have not made much changes to your code. so i think this maybe easy for you to understand.
enter code here
def changer():
ch=[]
h='Hello World' #I have put your string in a variable
for i in h:
ch.append(i)
for j in range(1,len(ch),2):
if h[j]!=' ':
ch[j]= '#'
s=''
for k in ch:
s=s+k
print(s)
changer()

Split a string, loop through it character by character, and replace specific ones?

I'm working on an assignment and have gotten stuck on a particular task. I need to write two functions that do similar things. The first needs to correct capitalization at the beginning of a sentence, and count when this is done. I've tried the below code:
def fix_capitalization(usrStr):
count = 0
fixStr = usrStr.split('.')
for sentence in fixStr:
if sentence[0].islower():
sentence[0].upper()
count += 1
print('Number of letters capitalized: %d' % count)
print('Edited text: %s' % fixStr)
Bu receive an out of range error. I'm getting an "Index out of range error" and am not sure why. Should't sentence[0] simply reference the first character in that particular string in the list?
I also need to replace certain characters with others, as shown below:
def replace_punctuation(usrStr):
s = list(usrStr)
exclamationCount = 0
semicolonCount = 0
for sentence in s:
for i in sentence:
if i == '!':
sentence[i] = '.'
exclamationCount += 1
if i == ';':
sentence[i] = ','
semicolonCount += 1
newStr = ''.join(s)
print(newStr)
print(semicolonCount)
print(exclamationCount)
But I'm struggling to figure out how to actually do the replacing once the character is found. Where am I going wrong here?
Thank you in advance for any help!
I would use str.capitalize over str.upper on one character. It also works correctly on empty strings. The other major improvement would be to use enumerate to also track the index as you iterate over the list:
def fix_capitalization(s):
sentences = [sentence.strip() for sentence in s.split('.')]
count = 0
for index, sentence in enumerate(sentences):
capitalized = sentence.capitalize()
if capitalized != sentence:
count += 1
sentences[index] = capitalized
result = '. '.join(sentences)
return result, count
You can take a similar approach to replacing punctuation:
replacements = {'!': '.', ';': ','}
def replace_punctuation(s):
l = list(s)
counts = dict.fromkeys(replacements, 0)
for index, item in enumerate(l):
if item in replacements:
l[index] = replacements[item]
counts[item] += 1
print("Replacement counts:")
for k, v in counts.items():
print("{} {:>5}".format(k, v))
return ''.join(l)
There are better ways to do these things but I'll try to change your code minimally so you will learn something.
The first function's issue is that when you split the sentence like "Hello." there will be two sentences in your fixStr list that the last one is an empty string; so the first index of an empty string is out of range. fix it by doing this.
def fix_capitalization(usrStr):
count = 0
fixStr = usrStr.split('.')
for sentence in fixStr:
# changed line
if sentence != "":
sentence[0].upper()
count += 1
print('Number of letters capitalized: %d' % count)
print('Edited text: %s' % fixStr)
In second snippet you are trying to write, when you pass a string to list() you get a list of characters of that string. So all you need to do is to iterate over the elements of the list and replace them and after that get string from the list.
def replace_punctuation(usrStr):
newStr = ""
s = list(usrStr)
exclamationCount = 0
semicolonCount = 0
for c in s:
if c == '!':
c = '.'
exclamationCount += 1
if c == ';':
c = ','
semicolonCount += 1
newStr = newStr + c
print(newStr)
print(semicolonCount)
print(exclamationCount)
Hope I helped!
Python has a nice build in function for this
for str in list:
new_str = str.replace('!', '.').replace(';', ',')
You can write a oneliner to get a new list
new_list = [str.replace('!', '.').replace(';', ',') for str in list]
You also could go for the split/join method
new_str = '.'.join(str.split('!'))
new_str = ','.join(str.split(';'))
To count capitalized letters you could do
result = len([cap for cap in str if str(cap).isupper()])
And to capitalize them words just use the
str.capitalize()
Hope this works out for you

Using a for loop to count the number of total letters and the number of a specific letter\

For a school project I have to write a function that counts the number of letters in a string, but also counts the number of a specific letter, however it only seems to increase the total letter count when it is the specified letter. I don't understand why it isn't registering ascii_lowercase as the lower case alphabet in 3.7, unless i have drastically misunderstood something.
def analyze_string(quote, search_letter):
count_letters = 0
count_occurance = 0
phrase = quote.lower()
letter = string.ascii_lowercase
length = len(phrase)
for i in phrase:
if i == letter:
count_letters = count_letters + 1
elif i == search_letter:
count_letters = count_letters + 1
count_occurance = count_occurance + 1
else:
count_letters = count_letters + 0
return count_letters, count_occurance
This line is problematic:
if i == letter:
You have assigned to letter a string containing all lowercase letters via string.ascii_lowercase. But i is just one letter. You can instead use:
if i in letter:
# ...
Checking membership of a string takes O(n) time. You may wish to use set to reduce this to O(1) beforehand via a conversion:
letter = set(string.ascii_lowercase)
You then need to reverse the order of your if statements so that the check for search_letter takes precedence. Otherwise, if search_letter exists in letter, the second condition will never be met.
for i in phrase:
if i == search_letter:
count_letters = count_letters + 1
count_occurance = count_occurance + 1
elif i in letter:
count_letters = count_letters + 1
Note the below lines are redundant, you can safely remove them:
else:
count_letters = count_letters + 0

Trouble with alternating string case

Working through exercises on the CodeWars website and I need help being pointed in the right direction for a simple function:
Write a function toWeirdCase (weirdcase in Ruby) that accepts a
string, and returns the same string with all even indexed characters
in each word upper cased, and all odd indexed characters in each word
lower cased. The indexing just explained is zero based, so the
zero-ith index is even, therefore that character should be upper
cased.
The passed in string will only consist of alphabetical characters and
spaces(' '). Spaces will only be present if there are multiple words.
Words will be separated by a single space(' ').
The code I have so far is this:
def to_weird_case(string):
#TODO
new_string = ''
add = 0
for letter in range(len(string)):
if string[letter] == ' ':
add += 1
new_string += string[letter]
continue
if (letter+add)%2 == 0:
new_string += string[letter].upper()
else:
new_string += string[letter].lower()
print("Returning: " + new_string)
return new_string
I am trying to iterate over each letter while taking in to account the spaces but I am unsure how to 'skip over' the spaces and that is what is messing up my function? If someone could point me in the right direction that would be helpful, thanks.
def to_weird_case(string):
#TODO
counter = 0
new_string = ''
add = 0
for letter in range(len(string)):
if string[letter] == ' ':
new_string += string[letter]
continue
if (counter)%2 == 0:
new_string += string[letter].upper()
else:
new_string += string[letter].lower()
# Increment counter after one place as 0th position is even
counter = counter + 1
print("Returning: " + new_string)
return new_string
to_weird_case("HELLO MY NAME IS abcdefghijk")
Output : Returning: HeLlO mY nAmE iS aBcDeFgHiJk
Just create a counter (an integer variable) that will keep track of whether you are in an even or odd index. The counter will not increment if you encounter a space, thereby ignoring it.
def to_weird_case(string):
#TODO
counter = 0
new_string = ''
add = 0
for letter in range(len(string)):
if string[letter] == ' ':
new_string += string[letter]
continue
# Increment counter only if not space
counter = counter + 1
if (counter)%2 == 0:
new_string += string[letter].upper()
else:
new_string += string[letter].lower()
print("Returning: " + new_string)
return new_string
You can disregard the spaces by first splitting the string using str.split, transform each word using enumerate to select even and odd characters, and then rejoin the string using str.join on spaces:
def transform_word(s):
return ''.join(x.upper() if i%2==0 else x.lower() for i, x in enumerate(s))
# ^------------^-> ternary operator for alternating
def to_weird_case(string):
return ' '.join(transform_word(s) for s in string.split())
print(to_weird_case('This is a lovely day'))
# ThIs Is A LoVeLy DaY
And if you eventually want to consider the spaces, use the transform_word function directly:
print(transform_word('This is a lovely day'))
# ThIs iS A LoVeLy dAy
Try list comprehension:
def my_func(your_string):
x = [ x.upper() if i%2==0 else x.lower() for i,x in enumerate(your_string)]
return ''.join(x)
your_string = 'hello my name is lmurdock12'
print(my_func(your_string))
Output:
HeLlO My nAmE Is lMuRdOcK12
So basically what happens in this list comprehension is that we use enumerate()
x = [ x.upper() if i%2==0 else x.lower() for i,x in enumerate(your_string)]
enumerate takes a iterable (string,list..etc) and gives out items one by one (i) where i would be 0,1,2,3...and so on
So in the list comprehension we check if i corresponding to that item x returned from iterable string your_list. So in hello my name is lmurdock12 i would be 0 for h and 1 for e and so on. If i%2==0 which means it's even we keep x.upper() else we keep x.lower() in the list.
Finally use ''.join(x) to join the list and return it if you want.
NOTE: This could be done without enumerate by using index() but that would make our algorithm a little inefficient because that we way we have search for the value and return index everytime. It's better to use enumerate.
Here is a working solution. Hope that helps!
def to_weird_case(string)
words = string.split(" ")
words.map do |word|
word.chars.map.with_index {|letter, idx| idx.even? ? letter.upcase : letter.downcase }.join("")
end.join(" ")
end
You can avoid the counter if you user the enumerate function
def to_weird_case(string):
#TODO
new_string = ''
for i,letter in enumerate(string):
if string[i] == ' ':
new_string += string[i]
continue
if i%2 == 0:
new_string += string[i].upper()
else:
new_string += string[i].lower()
print("Returning: " + new_string)
return new_string
Your code is not really pythonesque. Your function can actually have only 1 line of code. This is why Python is so cool.
def ToWeirdCase(word):
return ''.join([char.upper() if pos%2==0 else char.lower() for pos, char in enumerate(word)])
Hi I had this same problem early this morning, this is my answer:
def to_weird_case(sentence):
counter = 0 # Counter set to zero, because of the even number fact at zero-ith.
weird_sentence = "" # This is the string we are going to return at the end.
for character in sentence:
if character == " " and counter % 2 == 0:
weird_sentence += character
counter += 1 # Incrementation that will now make each characters before a space to be uppercased.
elif character != " " and counter % 2 == 0:
weird_sentence += character.upper()
else:
weird_sentence += character.lower()
counter += 1
return weird_sentence
I hope it helps you out.

Counting words starting with a character

Write a function that accepts a string and a character as input and
returns the count of all the words in the string which start with the
given character. Assume that capitalization does not matter here. You
can assume that the input string is a sentence i.e. words are
separated by spaces and consists of alphabetic characters.
This is my code:
def count_input_character (input_str, character):
input_str = input_str.lower()
character = character.lower()
count = 0
for i in range (0, len(input_str)):
if (input_str[i] == character and input_str[i - 1] == " "):
count += 1
return (count)
#Main Program
input_str = input("Enter a string: ")
character = input("Enter character whose occurances are to be found in the given input string: ")
result = count_input_character(input_str, character)
#print(result)
The only part missing here is that how to check if the first word of the sentence is stating with the user given character. consider this output:
Your answer is NOT CORRECT Your code was tested with different inputs. > For example when your function is called as shown below:
count_input_character ('the brahman the master of the universe', 't')
####### Your function returns ############# 2 The returned variable type is: type 'int'
### Correct return value should be ######## 3 The returned variable type is: type 'int'
You function misses the first t because in this line
if (input_str[i] == character and input_str[i - 1] == " "):
when i is 0, then input_str[i - 1] is input_str[-1] which Python will resolve as the last character of the string!
To fix this, you could change your condition to
if input_str[i] == character and (i == 0 or input_str[i - 1] == " "):
Or use str.split with a list comprehension. Or a regular expression like r'(?i)\b%s', with (?i) meaning "ignore case", \b is word boundary and %s a placeholder for the character..
Instead of looking for spaces, you could split input_str on whitespace, this would produce a list of words that you could then test against character. (Pseudocode below)
function F sentence, character {
l = <sentence split by whitespace>
count = 0
for word in l {
if firstchar(word) == character {
count = count + 1
}
}
return count
}
Although it doesn't fix your specific bug, for educational purposes, please note you could rewrite your function like this using list comprehension:
def count_input_character (input_str, character):
return len([x for x in input_str.lower().split() if x.startswith(character.lower())])
or even more efficiently(thanks to tobias_k)
def count_input_character (input_str, character):
sum(w.startswith(character.lower()) for w in input_str.lower().split())
def c_upper(text, char):
text = text.title() #set leading char of words to uppercase
char = char.upper() #set given char to uppercase
k = 0 #counter
for i in text:
if i.istitle() and i == char: #checking conditions for problem, where i is a char in a given string
k = k + 1
return k

Categories

Resources