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
Eventually I will be able to post simple questions like this in a chat room, but for now I must post it. I am still struggling with comparison issues in Python. I have a list containing strings that I obtained from a file. I have a function which takes in the word list (previously created from a file) and some 'ciphertext'. I am trying to Brute Force crack the ciphertext using a Shift Cipher. My issue is the same as with comparing integers. Although I can see when trying to debug using print statements, that my ciphertext will be shifted to a word in the word list, it never evaluates to True. I am probably comparing two different variable types or a /n is probably throwing the comparison off. Sorry for all of the posts today, I am doing lots of practice problems today in preparation for an upcoming assignment.
def shift_encrypt(s, m):
shiftAmt = s % 26
msgAsNumList = string2nlist(m)
shiftedNumList = add_val_mod26(msgAsNumList, shiftAmt)
print 'Here is the shifted number list: ', shiftedNumList
# Take the shifted number list and convert it back to a string
numListtoMsg = nlist2string(shiftedNumList)
msgString = ''.join(numListtoMsg)
return msgString
def add_val_mod26(nlist, value):
newValue = value % 26
print 'Value to Add after mod 26: ', newValue
listLen = len(nlist)
index = 0
while index < listLen:
nlist[index] = (nlist[index] + newValue) % 26
index = index + 1
return nlist
def string2nlist(m):
characters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
numbers = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
newList = []
msgLen = len(m) # var msgLen will be an integer of the length
index = 0 # iterate through message length in while loop
while index < msgLen:
letter = m[index] # iterate through message m
i = 0
while i < 26:
if letter == characters[i]:
newList.append(numbers[i])
i = i + 1
index = index + 1
return newList
def nlist2string(nlist):
characters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
numbers = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
newList = []
nListLen = len(nlist)
index = 0
while index < nListLen:
num = nlist[index]
newNum = num % 26
i = 0
while i < 26:
num1 = newNum
num2 = numbers[i]
if (num1 == num2):
newList.append(characters[i])
i = i + 1
index = index + 1
return newList
def wordList(filename):
fileObject = open(filename, "r+")
wordsList = fileObject.readlines()
return wordsList
def shift_computePlaintext(wlist, c):
index = 0
while index < 26:
newCipher = shift_encrypt(index, c)
print 'The new cipher text is: ', newCipher
wordlistLen = len(wlist)
i = 0
while i < wordlistLen:
print wlist[i]
if newCipher == wlist[i]:
return newCipher
else:
print 'Word not found.'
i = i + 1
index = index + 1
print 'Take Ciphertext and Find Plaintext from Wordlist Function: \n'
list = wordList('test.txt')
print list
plainText = shift_computePlaintext(list, 'vium')
print 'The plaintext was found in the wordlist: ', plainText
When the shift amount = 18, the ciphertext = name which is a word in my wordlist, but it never evaluates to True. Thanks for any help in advance!!
It's hard to be sure with the information we have so far, but here's a guess:
wordsList = fileObject.readlines()
This is going to return you a list of strings with the newlines preserved, like:
['hello\n', 'my\n', 'name\n', 'is\n', 'jesi\n']
So, inside shift_computePlaintext, when you iterate over wlist looking for something that matches the decrypted 'vium', you're looking for a string that matches 'name', and none of them match, including 'name\n'.
In other words, exactly what you suspected.
There are a few ways to fix this, but the most obvious are to use wlist[i].strip() instead of wlist[i], or to strip everything in the first place by using something like wordsList = [line.strip() for line in fileObject] instead of wordsList = fileObject.readlines().
A few side notes:
There is almost never a good reason to call readlines(). That returns a list of lines that you can iterate over… but the file object itself was already an iterable of lines that you can iterate over. If you really need to make sure it's a list instead of some other kind of iterable, or make a separate copy for later, or whatever, just call list on it, as you would with any other iterable.
You should almost never write a loop like this:
index = 0
while index < 26:
# ...
index = index + 1
Instead, just do this:
for index in range(26):
It's easier to read, harder to get wrong (subtle off-by-one errors are responsible for half the frustrating debugging you will do in your lifetime), etc.
And if you're looping over the length of a collection, don't even do that. Instead of this:
wordlistLen = len(wlist)
i = 0
while i < wordlistLen:
# ...
word = wlist[i]
# ...
i = i + 1
… just do this:
for word in wlist:
… or, if you need both i and word (which you occasionally do):
for i, word in enumerate(wlist):
Meanwhile, if the only reason you're looping over a collection is to check each of its values, you don't even need that. Instead of this:
wordlistLen = len(wlist)
while i < wordlistLen:
print wlist[i]
if newCipher == wlist[i]:
return newCipher
else:
print 'Word not found.'
i = i + 1
… just do this:
if newCipher in wlist:
return newCipher
else:
print 'Word not found.'
Here, you've actually got one of those subtle bugs: you print 'Word not found' over and over, instead of only printing it once at the end if it wasn't found.
How can I count the number of times a given substring is present within a string in Python?
For example:
>>> 'foo bar foo'.numberOfOccurrences('foo')
2
To get indices of the substrings, see How to find all occurrences of a substring?.
string.count(substring), like in:
>>> "abcdabcva".count("ab")
2
This is for non overlapping occurrences.
If you need to count overlapping occurrences, you'd better check the answers here, or just check my other answer below.
s = 'arunununghhjj'
sb = 'nun'
results = 0
sub_len = len(sb)
for i in range(len(s)):
if s[i:i+sub_len] == sb:
results += 1
print results
Depending what you really mean, I propose the following solutions:
You mean a list of space separated sub-strings and want to know what is the sub-string position number among all sub-strings:
s = 'sub1 sub2 sub3'
s.split().index('sub2')
>>> 1
You mean the char-position of the sub-string in the string:
s.find('sub2')
>>> 5
You mean the (non-overlapping) counts of appearance of a su-bstring:
s.count('sub2')
>>> 1
s.count('sub')
>>> 3
The best way to find overlapping sub-strings in a given string is to use a regular expression. With lookahead, it will find all the overlapping matches using the regular expression library's findall(). Here, left is the substring and right is the string to match.
>>> len(re.findall(r'(?=aa)', 'caaaab'))
3
To find overlapping occurences of a substring in a string in Python 3, this algorithm will do:
def count_substring(string,sub_string):
l=len(sub_string)
count=0
for i in range(len(string)-len(sub_string)+1):
if(string[i:i+len(sub_string)] == sub_string ):
count+=1
return count
I myself checked this algorithm and it worked.
You can count the frequency using two ways:
Using the count() in str:
a.count(b)
Or, you can use:
len(a.split(b))-1
Where a is the string and b is the substring whose frequency is to be calculated.
Scenario 1: Occurrence of a word in a sentence.
eg: str1 = "This is an example and is easy". The occurrence of the word "is". lets str2 = "is"
count = str1.count(str2)
Scenario 2 : Occurrence of pattern in a sentence.
string = "ABCDCDC"
substring = "CDC"
def count_substring(string,sub_string):
len1 = len(string)
len2 = len(sub_string)
j =0
counter = 0
while(j < len1):
if(string[j] == sub_string[0]):
if(string[j:j+len2] == sub_string):
counter += 1
j += 1
return counter
Thanks!
The current best answer involving method count doesn't really count for overlapping occurrences and doesn't care about empty sub-strings as well.
For example:
>>> a = 'caatatab'
>>> b = 'ata'
>>> print(a.count(b)) #overlapping
1
>>>print(a.count('')) #empty string
9
The first answer should be 2 not 1, if we consider the overlapping substrings.
As for the second answer it's better if an empty sub-string returns 0 as the asnwer.
The following code takes care of these things.
def num_of_patterns(astr,pattern):
astr, pattern = astr.strip(), pattern.strip()
if pattern == '': return 0
ind, count, start_flag = 0,0,0
while True:
try:
if start_flag == 0:
ind = astr.index(pattern)
start_flag = 1
else:
ind += 1 + astr[ind+1:].index(pattern)
count += 1
except:
break
return count
Now when we run it:
>>>num_of_patterns('caatatab', 'ata') #overlapping
2
>>>num_of_patterns('caatatab', '') #empty string
0
>>>num_of_patterns('abcdabcva','ab') #normal
2
The question isn't very clear, but I'll answer what you are, on the surface, asking.
A string S, which is L characters long, and where S[1] is the first character of the string and S[L] is the last character, has the following substrings:
The null string ''. There is one of these.
For every value A from 1 to L, for every value B from A to L, the string S[A]..S[B]
(inclusive). There are L + L-1 + L-2 + ... 1 of these strings, for a
total of 0.5*L*(L+1).
Note that the second item includes S[1]..S[L],
i.e. the entire original string S.
So, there are 0.5*L*(L+1) + 1 substrings within a string of length L. Render that expression in Python, and you have the number of substrings present within the string.
One way is to use re.subn. For example, to count the number of
occurrences of 'hello' in any mix of cases you can do:
import re
_, count = re.subn(r'hello', '', astring, flags=re.I)
print('Found', count, 'occurrences of "hello"')
How about a one-liner with a list comprehension? Technically its 93 characters long, spare me PEP-8 purism. The regex.findall answer is the most readable if its a high level piece of code. If you're building something low level and don't want dependencies, this one is pretty lean and mean. I'm giving the overlapping answer. Obviously just use count like the highest score answer if there isn't overlap.
def count_substring(string, sub_string):
return len([i for i in range(len(string)) if string[i:i+len(sub_string)] == sub_string])
If you want to count all the sub-string (including overlapped) then use this method.
import re
def count_substring(string, sub_string):
regex = '(?='+sub_string+')'
# print(regex)
return len(re.findall(regex,string))
I will keep my accepted answer as the "simple and obvious way to do it", however, it does not cover overlapping occurrences.
Finding out those can be done naively, with multiple checking of the slices - as in:
sum("GCAAAAAGH"[i:].startswith("AAA") for i in range(len("GCAAAAAGH")))
which yields 3.
Or it can be done by trick use of regular expressions, as can be seen at How to use regex to find all overlapping matches - and it can also make for fine code golfing.
This is my "hand made" count for overlapping occurrences of patterns in a string which tries not to be extremely naive (at least it does not create new string objects at each interaction):
def find_matches_overlapping(text, pattern):
lpat = len(pattern) - 1
matches = []
text = array("u", text)
pattern = array("u", pattern)
indexes = {}
for i in range(len(text) - lpat):
if text[i] == pattern[0]:
indexes[i] = -1
for index, counter in list(indexes.items()):
counter += 1
if text[i] == pattern[counter]:
if counter == lpat:
matches.append(index)
del indexes[index]
else:
indexes[index] = counter
else:
del indexes[index]
return matches
def count_matches(text, pattern):
return len(find_matches_overlapping(text, pattern))
For overlapping count we can use use:
def count_substring(string, sub_string):
count=0
beg=0
while(string.find(sub_string,beg)!=-1) :
count=count+1
beg=string.find(sub_string,beg)
beg=beg+1
return count
For non-overlapping case we can use count() function:
string.count(sub_string)
Overlapping occurences:
def olpcount(string,pattern,case_sensitive=True):
if case_sensitive != True:
string = string.lower()
pattern = pattern.lower()
l = len(pattern)
ct = 0
for c in range(0,len(string)):
if string[c:c+l] == pattern:
ct += 1
return ct
test = 'my maaather lies over the oceaaan'
print test
print olpcount(test,'a')
print olpcount(test,'aa')
print olpcount(test,'aaa')
Results:
my maaather lies over the oceaaan
6
4
2
Here's a solution that works for both non-overlapping and overlapping occurrences. To clarify: an overlapping substring is one whose last character is identical to its first character.
def substr_count(st, sub):
# If a non-overlapping substring then just
# use the standard string `count` method
# to count the substring occurences
if sub[0] != sub[-1]:
return st.count(sub)
# Otherwise, create a copy of the source string,
# and starting from the index of the first occurence
# of the substring, adjust the source string to start
# from subsequent occurences of the substring and keep
# keep count of these occurences
_st = st[::]
start = _st.index(sub)
cnt = 0
while start is not None:
cnt += 1
try:
_st = _st[start + len(sub) - 1:]
start = _st.index(sub)
except (ValueError, IndexError):
return cnt
return cnt
If you're looking for a power solution that works every case this function should work:
def count_substring(string, sub_string):
ans = 0
for i in range(len(string)-(len(sub_string)-1)):
if sub_string == string[i:len(sub_string)+i]:
ans += 1
return ans
If you want to find out the count of substring inside any string; please use below code.
The code is easy to understand that's why i skipped the comments. :)
string=raw_input()
sub_string=raw_input()
start=0
answer=0
length=len(string)
index=string.find(sub_string,start,length)
while index<>-1:
start=index+1
answer=answer+1
index=string.find(sub_string,start,length)
print answer
You could use the startswith method:
def count_substring(string, sub_string):
x = 0
for i in range(len(string)):
if string[i:].startswith(sub_string):
x += 1
return x
def count_substring(string, sub_string):
inc = 0
for i in range(0, len(string)):
slice_object = slice(i,len(sub_string)+i)
count = len(string[slice_object])
if(count == len(sub_string)):
if(sub_string == string[slice_object]):
inc = inc + 1
return inc
if __name__ == '__main__':
string = input().strip()
sub_string = input().strip()
count = count_substring(string, sub_string)
print(count)
def count_substring(string, sub_string):
k=len(string)
m=len(sub_string)
i=0
l=0
count=0
while l<k:
if string[l:l+m]==sub_string:
count=count+1
l=l+1
return count
if __name__ == '__main__':
string = input().strip()
sub_string = input().strip()
count = count_substring(string, sub_string)
print(count)
2+ others have already provided this solution, and I even upvoted one of them, but mine is probably the easiest for newbies to understand.
def count_substring(string, sub_string):
slen = len(string)
sslen = len(sub_string)
range_s = slen - sslen + 1
count = 0
for i in range(range_s):
if string[i:i+sslen] == sub_string:
count += 1
return count
I'm not sure if this is something looked at already, but I thought of this as a solution for a word that is 'disposable':
for i in xrange(len(word)):
if word[:len(term)] == term:
count += 1
word = word[1:]
print count
Where word is the word you are searching in and term is the term you are looking for
string="abc"
mainstr="ncnabckjdjkabcxcxccccxcxcabc"
count=0
for i in range(0,len(mainstr)):
k=0
while(k<len(string)):
if(string[k]==mainstr[i+k]):
k+=1
else:
break
if(k==len(string)):
count+=1;
print(count)
my_string = """Strings are amongst the most popular data types in Python.
We can create the strings by enclosing characters in quotes.
Python treats single quotes the same as double quotes."""
Count = my_string.lower().strip("\n").split(" ").count("string")
Count = my_string.lower().strip("\n").split(" ").count("strings")
print("The number of occurance of word String is : " , Count)
print("The number of occurance of word Strings is : " , Count)
For a simple string with space delimitation, using Dict would be quite fast, please see the code as below
def getStringCount(mnstr:str, sbstr:str='')->int:
""" Assumes two inputs string giving the string and
substring to look for number of occurances
Returns the number of occurances of a given string
"""
x = dict()
x[sbstr] = 0
sbstr = sbstr.strip()
for st in mnstr.split(' '):
if st not in [sbstr]:
continue
try:
x[st]+=1
except KeyError:
x[st] = 1
return x[sbstr]
s = 'foo bar foo test one two three foo bar'
getStringCount(s,'foo')
Below logic will work for all string & special characters
def cnt_substr(inp_str, sub_str):
inp_join_str = ''.join(inp_str.split())
sub_join_str = ''.join(sub_str.split())
return inp_join_str.count(sub_join_str)
print(cnt_substr("the sky is $blue and not greenthe sky is $blue and not green", "the sky"))
Here's the solution in Python 3 and case insensitive:
s = 'foo bar foo'.upper()
sb = 'foo'.upper()
results = 0
sub_len = len(sb)
for i in range(len(s)):
if s[i:i+sub_len] == sb:
results += 1
print(results)
j = 0
while i < len(string):
sub_string_out = string[i:len(sub_string)+j]
if sub_string == sub_string_out:
count += 1
i += 1
j += 1
return count
#counting occurence of a substring in another string (overlapping/non overlapping)
s = input('enter the main string: ')# e.g. 'bobazcbobobegbobobgbobobhaklpbobawanbobobobob'
p=input('enter the substring: ')# e.g. 'bob'
counter=0
c=0
for i in range(len(s)-len(p)+1):
for j in range(len(p)):
if s[i+j]==p[j]:
if c<len(p):
c=c+1
if c==len(p):
counter+=1
c=0
break
continue
else:
break
print('number of occurences of the substring in the main string is: ',counter)