Another capitalise every odd char of the string solution

Question:

I just started studying Python and created some kind of task for myself that I’m struggling to solve…

So, I’m on chapter on working with strings (accessing strings by index, changing etc).

My task is – capitalize every odd char of the string. I saw the solution here: Capitalise every other letter in a string in Python?

but I don’t like it… wanted to solve this by slices. So what I produced is followig code:

T = 'somesampletexthere'  
R=""

for i in range(0, len(T[1::2])):
        R+=T[::2][i].upper()+T[1::2][i].lower()

print R

This code works great when there are even number of chars, for example with TESTTEXT but when the number is odd like here in EXAMPLE it will skipp last char (in this case E)

This is because the range is till len(T[1::2])) (length of even characters) but if I’ll try the length of odd characters len(T[::2])) I’ll get error:

IndexError: string index out of range

logically because number of odd chars will always be bigger on 1 (in case of text with odd number of characters).

So, my question is – how can I supress the error? So Python just return null or something in case the index is out of range of the given string?

Or any other solutions of the task using slices?

Asked By: Akhiles

||

Answers:

You could just use enumerate and test for odd and even indices using a ternary operator. Then use join to join the string:

>>> T = 'somesampletexthere'
>>> ''.join(x.upper() if i%2 else x.lower() for i, x in enumerate(T))
'sOmEsAmPlEtExThErE'

You could handle whitespaces by using an external counter object provided by itertools.count:

>>> from itertools import count
>>> c = count()
>>> T = 'some sample text here'
>>> ''.join(x if x.isspace() else (x.upper() if next(c)%2 else x.lower()) for x in T)
'sOmE sAmPlE tExT hErE'
Answered By: Moses Koledoye

Your are right to prefer a slicing solution over those in the linked question. (OTOH, that’s a slightly different question because it skips spaces). However, your current code is rather inefficient because it recreates the T[::2] and T[1::2] slices on every iteration of the for loop. Also, calling .upper or .lower on single characters is less efficient than calling it on larger strings.

Here’s an efficient way to do this using slicing.

T = 'somesampletexthere'
R = [''] * len(T)
R[::2], R[1::2] = T[::2].upper(), T[1::2].lower()
R = ''.join(R)
print(R)

output

SoMeSaMpLeTeXtHeRe

It may help you understand what’s going on if we split up those assignments to R.

T = 'somesampletexthere'
R = [''] * len(T)
R[::2] = T[::2].upper()
print(R)
R[1::2] = T[1::2].lower()
print(R)
R = ''.join(R)
print(R)

output

['S', '', 'M', '', 'S', '', 'M', '', 'L', '', 'T', '', 'X', '', 'H', '', 'R', '']
['S', 'o', 'M', 'e', 'S', 'a', 'M', 'p', 'L', 'e', 'T', 'e', 'X', 't', 'H', 'e', 'R', 'e']
SoMeSaMpLeTeXtHeRe

We can do those slice assignments in either order:

T = 'somesampletexthere'
R = [''] * len(T)
R[1::2] = T[1::2].lower()
print(R)
R[::2] = T[::2].upper()
print(R)
R = ''.join(R)
print(R)

output

['', 'o', '', 'e', '', 'a', '', 'p', '', 'e', '', 'e', '', 't', '', 'e', '', 'e']
['S', 'o', 'M', 'e', 'S', 'a', 'M', 'p', 'L', 'e', 'T', 'e', 'X', 't', 'H', 'e', 'R', 'e']
SoMeSaMpLeTeXtHeRe

Just for fun, here’s an alternative strategy that zips the upper & lower case strings together. We use izip_longest (or zip_longest in Python 3) so we can handle strings that have an odd length.

from itertools import izip_longest

T = 'somesampletexthere'
R = ''.join([c for t in izip_longest(T[::2].upper(), T[1::2].lower(), fillvalue='') for c in t])
print(R)

Although this version does it in one line I prefer my first version: I find it more readable, and it’s probably a little faster.

Answered By: PM 2Ring

Strings are not mutable, but lists are. So, we can create a list of lowercase characters of the string (from .lower()), use slice assignment to replace the appropriate ones with uppercase, and join them all back together:

lower_chars = list(T.lower())
lower_chars[::2] = T[::2].upper()
R = ''.join(lower_chars)
Answered By: Karl Knechtel
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.