Writing word wrapping function using recursion in Python? - python

def insertNewLine(text, lenght):
if len(text) < lenght:
return text
else:
print text[:lenght]
return (text[:lenght]+'\n'+ insertNewLine(text[lenght:],lenght))
but the problem is that word is dividing by my program .. that should not happen.. e.g.
=> Input :
"Random text to wrap again." and Lenght: 5
=> My Output:
Rando
m tex
t to
wrap
again
.
=> Expected Output:
Random
text
to wrap
again.

It looks like you need to wrap on whole words after a certain length, and ignoring spaces; I'd do something like this:
def wrap(text, length):
words = text.split()
lines = []
line = ''
for w in words:
if len(w) + len(line) > length:
lines.append(line)
line = ''
line = line + w + ' '
if w is words[-1]: lines.append(line)
return '\n'.join(lines)
This basically works by splitting the text into whole words, and then assembling lines of them up to your wrap length. That way you don't have to figure out if you're trying to break in the middle of a word. I didn't bother to check whether your length is shorter than your longest word, but that's a consideration as well.

def insertNewLine(text, lenght):
if len(text) < lenght:
return text
else:
print text[:lenght]
return (text[:lenght]+'\n'+ insertNewLine(text[lenght:],lenght))
"Random text to wrap again." and Lenght: 5
The problem is that you are saying with
'\n'
That you want a new line ever 5 characters. The word Random has 6 which is why it is being cut at Rando. Also remember that the spaces count as a character as well. So when your recursion goes through it is simply counting 5 characters and then inserting a new line every 5.

This is a posible solution to your problem, I use re python module to put \n characters in the right place.
import re
def insertNewLine(text, lenght):
return re.sub('((.*){' + str(lenght-1) + ',}?)\s', '\g<1>\n', text)
if __name__ == "__main__":
print insertNewLine("Random text to wrap again.", 5)
>>>python test.py
Random
text
to wrap
again.

def insertNewline(text, length):
'''
This function can only be applied to normal text.
'''
if len(text) <= length:
print(text)
return
elif text[length - 1] == ' ':
print(text[:length - 1])
return insertNewline(text[(length):], length)
elif text[length] == ' ':
print(text[:length])
return insertNewline(text[(length + 1):], length)
else:
i = 0
while text[length + i] != ' ' and text[length + i] != ',' and text[length + i] != '.':
i += 1
if text[length + i] == ' ':
print(text[:(length + i)])
return insertNewline(text[(length + i + 1):], length)
else:
print(text[:(length + i + 1)])
return insertNewline(text[(length + i + 2):], length)
This code works correctly with normal text, by which I mean simple English sentences with only ',' and '.' as punctuations, and after each punctuation there is only one space, just as normal essay writing. If you want to apply this code to more complete text, I think you can update this code by yourself.
I use "recursion" as you required in your question. I think this code should be helpful for you.
I'm not an expert in python, and still in the learning process. Hope you can get what you want from my answer.

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

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

How do I create a word count that does not include blank spaces?

I am a beginner to python, and I was tasked with creating a function that accepts a string as the parameter and return the number of words in the string.
I am having trouble with the spaces and the blank string I assigned. I feel like I am missing something, but am a bit lost as to what's missing or what I've messed up. Also we can't use split.
Any guidance or help would be greatly appreciated
This is what I have so far:
def word_count(str):
count = 1
for i in str:
if (i == ' '):
count += 1
print (count)
word_count('hello') --> Output = 1 (so far correct)
word_count('how are you?') --> Output = 3 (also correct/at least what i am looking for)
word_count(' this string has wide spaces ') --> Output = 7 (Should be 5...)
word_count(' ') --> Output = 2 (Should be ''. I think it's doing count(1+1))
use this code as an improvement
def word_count(str):
count = 1
for i in str:
if (i == ' '):
count += 1
if str[0] == ' ':
count -= 1
if str[-1] == ' ':
count -= 1
print (count)
your error is because your counting spaces if they start at beginning or appear at end.
NOTE that you can't pass empty string "" since this is evaluated to NONE, and trying to index it will cause an error
The problem seems to be when there is a blank in front or behind the sentence. A way to fix this is by using a built in function 'strip'. For example, we can do the following:
example_string = " This is a string "
print(example_string)
stripped_string = example_string.strip()
print(stripped_string)
The output of the first string will be
" This is a string "
The output of the second string will be
"This is a string"
What you can do is the following:
def word_count(input_str):
return len(input_str.split())
count = word_count(' this is a test ')
print (count)
It basically removes the leading/trailing spaces and splits the phrase into
a list.
If, on the offchance you need to use a loop:
def word_count(input_str):
count = 0
input_str = input_str.strip()
for i in input_str:
if (i == ' '):
count += 1
return count
count = word_count(' this is a test ')
print (count)

Removing And Re-Inserting Spaces

What is the most efficient way to remove spaces from a text, and then after the neccessary function has been performed, re-insert the previously removed spacing?
Take this example below, here is a program for encoding a simple railfence cipher:
from string import ascii_lowercase
string = "Hello World Today"
string = string.replace(" ", "").lower()
print(string[::2] + string[1::2])
This outputs the following:
hlooltdyelwrdoa
This is because it must remove the spacing prior to encoding the text. However, if I now want to re-insert the spacing to make it:
hlool tdyel wrdoa
What is the most efficient way of doing this?
As mentioned by one of the other commenters, you need to record where the spaces came from then add them back in
from string import ascii_lowercase
string = "Hello World Today"
# Get list of spaces
spaces = [i for i,x in enumerate(string) if x == ' ']
string = string.replace(" ", "").lower()
# Set string with ciphered text
ciphered = (string[::2] + string[1::2])
# Reinsert spaces
for space in spaces:
ciphered = ciphered[:space] + ' ' + ciphered[space:]
print(ciphered)
You could use str.split to help you out. When you split on spaces, the lengths of the remaining segments will tell you where to split the processed string:
broken = string.split(' ')
sizes = list(map(len, broken))
You'll need the cumulative sum of the sizes:
from itertools import accumulate, chain
cs = accumulate(sizes)
Now you can reinstate the spaces:
processed = ''.join(broken).lower()
processed = processed[::2] + processed[1::2]
chunks = [processed[index:size] for index, size in zip(chain([0], cs), sizes)]
result = ' '.join(chunks)
This solution is not especially straightforward or efficient, but it does avoid explicit loops.
Using list and join operation,
random_string = "Hello World Today"
space_position = [pos for pos, char in enumerate(random_string) if char == ' ']
random_string = random_string.replace(" ", "").lower()
random_string = list(random_string[::2] + random_string[1::2])
for index in space_position:
random_string.insert(index, ' ')
random_string = ''.join(random_string)
print(random_string)
I think this might Help
string = "Hello World Today"
nonSpaceyString = string.replace(" ", "").lower()
randomString = nonSpaceyString[::2] + nonSpaceyString[1::2]
spaceSet = [i for i, x in enumerate(string) if x == " "]
for index in spaceSet:
randomString = randomString[:index] + " " + randomString[index:]
print(randomString)
string = "Hello World Today"
# getting index of ' '
index = [i for i in range(len(string)) if string[i]==' ']
# storing the non ' ' characters
data = [i for i in string.lower() if i!=' ']
# applying cipher code as mention in OP STATEMENT
result = data[::2]+data[1::2]
# inserting back the spaces in there position as they had in original string
for i in index:
result.insert(i, ' ')
# creating a string solution
solution = ''.join(result)
print(solution)
# output hlool tdyel wrdoa
You can make a new string with this small yet simple (kind of) code:
Note this doesn't use any libraries, which might make this slower, but less confusing.
def weird_string(string): # get input value
spaceless = ''.join([c for c in string if c != ' ']) # get spaceless version
skipped = spaceless[::2] + spaceless[1::2] # get new unique 'code'
result = list(skipped) # get list of one letter strings
for i in range(len(string)): # loop over strings
if string[i] == ' ': # if a space 'was' here
result.insert(i, ' ') # add the space back
# end for
s = ''.join(result) # join the results back
return s # return the result

How to remove or strip off white spaces without using strip() function?

Write a function that accepts an input string consisting of alphabetic
characters and removes all the leading whitespace of the string and
returns it without using .strip(). For example if:
input_string = " Hello "
then your function should return a string such as:
output_string = "Hello "
The below is my program for removing white spaces without using strip:
def Leading_White_Space (input_str):
length = len(input_str)
i = 0
while (length):
if(input_str[i] == " "):
input_str.remove()
i =+ 1
length -= 1
#Main Program
input_str = " Hello "
result = Leading_White_Space (input_str)
print (result)
I chose the remove function as it would be easy to get rid off the white spaces before the string 'Hello'. Also the program tells to just eliminate the white spaces before the actual string. By my logic I suppose it not only eliminates the leading but trailing white spaces too. Any help would be appreciated.
You can loop over the characters of the string and stop when you reach a non-space one. Here is one solution :
def Leading_White_Space(input_str):
for i, c in enumerate(input_str):
if c != ' ':
return input_str[i:]
Edit :
#PM 2Ring mentionned a good point. If you want to handle all types of types of whitespaces (e.g \t,\n,\r), you need to use isspace(), so a correct solution could be :
def Leading_White_Space(input_str):
for i, c in enumerate(input_str):
if not c.isspace():
return input_str[i:]
Here's another way to strip the leading whitespace, that actually strips all leading whitespace, not just the ' ' space char. There's no need to bother tracking the index of the characters in the string, we just need a flag to let us know when to stop checking for whitespace.
def my_lstrip(input_str):
leading = True
for ch in input_str:
if leading:
# All the chars read so far have been whitespace
if not ch.isspace():
# The leading whitespace is finished
leading = False
# Start saving chars
result = ch
else:
# We're past the whitespace, copy everything
result += ch
return result
# test
input_str = " \n \t Hello "
result = my_lstrip(input_str)
print(repr(result))
output
'Hello '
There are various other ways to do this. Of course, in a real program you'd simply use the string .lstrip method, but here are a couple of cute ways to do it using an iterator:
def my_lstrip(input_str):
it = iter(input_str)
for ch in it:
if not ch.isspace():
break
return ch + ''.join(it)
and
def my_lstrip(input_str):
it = iter(input_str)
ch = next(it)
while ch.isspace():
ch = next(it)
return ch + ''.join(it)
Use re.sub
>>> input_string = " Hello "
>>> re.sub(r'^\s+', '', input_string)
'Hello '
or
>>> def remove_space(s):
ind = 0
for i,j in enumerate(s):
if j != ' ':
ind = i
break
return s[ind:]
>>> remove_space(input_string)
'Hello '
>>>
Just to be thorough and without using other modules, we can also specify which whitespace to remove (leading, trailing, both or all), including tab and new line characters. The code I used (which is, for obvious reasons, less compact than other answers) is as follows and makes use of slicing:
def no_ws(string,which='left'):
"""
Which takes the value of 'left'/'right'/'both'/'all' to remove relevant
whitespace.
"""
remove_chars = (' ','\n','\t')
first_char = 0; last_char = 0
if which in ['left','both']:
for idx,letter in enumerate(string):
if not first_char and letter not in remove_chars:
first_char = idx
break
if which == 'left':
return string[first_char:]
if which in ['right','both']:
for idx,letter in enumerate(string[::-1]):
if not last_char and letter not in remove_chars:
last_char = -(idx + 1)
break
return string[first_char:last_char+1]
if which == 'all':
return ''.join([s for s in string if s not in remove_chars])
you can use itertools.dropwhile to remove all particualar characters from the start of you string like this
import itertools
def my_lstrip(input_str,remove=" \n\t"):
return "".join( itertools.dropwhile(lambda x:x in remove,input_str))
to make it more flexible, I add an additional argument called remove, they represent the characters to remove from the string, with a default value of " \n\t", then with dropwhile it will ignore all characters that are in remove, to check this I use a lambda function (that is a practical form of write short anonymous functions)
here a few tests
>>> my_lstrip(" \n \t Hello ")
'Hello '
>>> my_lstrip(" Hello ")
'Hello '
>>> my_lstrip(" \n \t Hello ")
'Hello '
>>> my_lstrip("--- Hello ","-")
' Hello '
>>> my_lstrip("--- Hello ","- ")
'Hello '
>>> my_lstrip("- - - Hello ","- ")
'Hello '
>>>
the previous function is equivalent to
def my_lstrip(input_str,remove=" \n\t"):
i=0
for i,x in enumerate(input_str):
if x not in remove:
break
return input_str[i:]

Categories

Resources