Reversing words in place - python

Ex. Input: rat the ate cat the
Output: the cat ate the rat
Here's my code so far:
def reverse_message(starting, ending, msg):
while(starting < ending):
msg[starting], msg[ending] = msg[ending], msg[starting]
starting += 1
ending -= 1
def reverse_words(msg):
# Decode the message by reversing the words
# reverse entire message
reverse_message(0, len(msg) - 1, msg)
#reverse each word
starting = 0
for i in range(len(msg)):
if ((msg[i] == ' ') or (i == len(msg) - 1)):
reverse_message(starting, i-1, msg)
starting = i+1
What am I doing wrong? Any help would be highly appreciated.

This can be done in a single line:
str=' '.join(list(input().split(' '))[::-1])

To begin with, I would avoid explicitly passing a starting and ending index, instead relying on the message itself, where starting index is the first, and the ending index is the last index of the string, also I will pass the string as a list, since strings are mutable and cannot be changed, but list can.
def reverse_word(msg):
starting = 0
ending = len(msg)-1
while(starting < ending):
tmp = msg[starting]
msg[starting] = msg[ending]
msg[ending] = tmp
starting += 1
ending -= 1
return msg
After that, to reverse the string, I will reverse the entire string first, and then reverse each word in the string in place, and then stitch the string back together for the output.
def reverse_message(msg):
#Convert the string into list of characters
chars = list(msg)
#Reverse entire list
chars = reverse_word(chars)
starting = 0
i = 0
result = []
#Iterate through the reversed list, and pick individual words based on
#whitespace, and then reverse them in place
while i < len(chars):
if chars[i] == ' ':
#Append all reversed words to another list
result += reverse_word(chars[starting:i]) + [' ']
starting = i+1
i+=1
#Reverse the last remaining word
result += reverse_word(chars[starting:i])
#Stitch the list back to string and return it
return ''.join(result)
The resultant output will look like.
print(reverse_message('rat the ate cat the'))
#the cat ate the rat

Related

A single line with the inputs assembled in Camel Case

I'm trying to reformat a series of strings into Camel Case by returning the fragments from input as a single "sentence".
this is what I have so far -
def convert(s):
if(len(s) == 0):
return
s1 = ''
s1 += s[0].upper()
for i in range(1, len(s)):
if (s[i] == ' '):
s1 += s[i + 1].upper()
i += 1
elif(s[i - 1] != ' '):
s1 += s[i]
print(s1)
# Driver Code
def main():
s = "BusOneBusTWOBUSthree"
convert(s)
if __name__=="__main__":
main()
output I'm getting is -
Bus One
Bus TWO
BUS three
output I'm wanting to get is -
busOne busTwo busThree
It looks like your example s= won't get you the output you say you're getting, so I am guessing that your input is space separated. It looks like you want to alternatively join 2 words together and make the 2nd word's first letter Uppercase. If so, split the string into a list, then iterate through the list and add to your final string. Here's one way to do that:
original_string = 'buS one buS two bus thRee'
original_string = original_string.lower()
list_of_words = original_string.split()
# splits on space by default, or specify 'x' to split on the letter x
camel_case_output = ''
for i in range(len(list_of_words)):
this_word = list_of_words[i]
if i % 2 == 0: # even numbers
camel_case_output += list_of_words[i]
else:
this_word = this_word[0].upper() + this_word[1:]
camel_case_output += this_word + ' '
camel_case_output.strip() # remove the last space, if you ended with extra

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

Find out word at specific index

I have a string with multiple words separated by underscores like this:
string = 'this_is_my_string'
And let's for example take string[n] which will return a letter.
Now for this index I want to get the whole word between the underscores.
So for string[12] I'd want to get back the word 'string' and for string[1] I'd get back 'this'
Very simple approach using string slicing is to:
slice the list in two parts based on position
split() each part based on _.
concatenate last item from part 1 and first item from part 2
Sample code:
>>> my_string = 'this_is_my_sample_string'
# ^ index 14
>>> pos = 14
>>> my_string[:pos].split('_')[-1] + my_string[pos:].split('_')[0]
'sample'
This shuld work:
string = 'this_is_my_string'
words = string.split('_')
idx = 0
indexes = {}
for word in words:
for i in range(len(word)):
idx += 1
indexes[idx] = word
print(indexes[1]) # this
print(indexes[12]) #string
The following code works. You can change the index and string variables and adapt to new strings. You can also define a new function with the code to generalize it.
string = 'this_is_my_string'
sp = string.split('_')
index = 12
total_len = 0
for word in sp:
total_len += (len(word) + 1) #The '+1' accounts for the underscore
if index < total_len:
result = word
break
print result
A little bit of regular expression magic does the job:
import re
def wordAtIndex(text, pos):
p = re.compile(r'(_|$)')
beg = 0
for m in p.finditer(text):
#(end, sym) = (m.start(), m.group())
#print (end, sym)
end = m.start()
if pos < end: # 'pos' is within current split piece
break
beg = end+1 # advance to next split piece
if pos == beg-1: # handle case where 'pos' is index of split character
return ""
else:
return text[beg:end]
text = 'this_is_my_string'
for i in range(0, len(text)+1):
print ("Text["+str(i)+"]: ", wordAtIndex(text, i))
It splits the input string at '_' characters or at end-of-string, and then iteratively compares the given position index with the actual split position.

Python: Specific List Output Inconsistency

I believe the output I'm getting is a product of sloppy code somewhere, but I can't seem to get it. What I want my function to do is make a new list of the elements in a list it's being passed, in those elements' Pig-Latin translation. I've got the function working, but it makes all of the new list elements the Pig-Latin translation of only the first element in the list being passed to the function, even though I'm using an index to iterate through the elements of the passed list.
def pigLatin(targetlist):
newlist = ()
listnewlist = list(newlist)
index = 0 # gets incremented
firstletter = targetlist[index][0]
word = targetlist[index][1:]
print('Words made into Pig Latin: ')
while index < len(targetlist):
listnewlist.append(word + firstletter + 'ay')
index += 1
print(listnewlist)
which, after user input is "how now brown cow", displays:
['owhay', 'owhay', 'owhay', 'owhay']
word and firstletter are both computed outside of the loop and keep the value of first word of the targetlist.
IMHO, you should write :
def pigLatin(targetlist):
newlist = ()
listnewlist = list(newlist)
index = 0 # gets incremented
print('Words made into Pig Latin: ')
while index < len(targetlist):
firstletter = targetlist[index][0]
word = targetlist[index][1:]
listnewlist.append(word + firstletter + 'ay')
index += 1
print(listnewlist)

Python String Comparisons Using A Word List

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.

Categories

Resources