Slicing strings
A Telebirr message tells you what you paid, but the amount is buried in a sentence. By the end of this lesson you'll cut exactly the piece you need out of a string, reverse a string, and know why slicing past the end never crashes.
A slice takes what's there
In lesson 1.3, "Selam"[5] was an IndexError: there is no position 5. Predict this
one, which asks for positions 1 to 100.
What will this print?
Decide before you look. Guessing wrong is how this sticks.
print("Selam"[1:100])Python prints
elam
A slice takes the characters from 1 up to 100 that exist, and stops quietly at the end. Only a single index has to exist.
You met the
in lesson 4.1 with lists, and it works the same on strings. text[start:stop] begins
at position
and ends just before position
.
Like every string method, a slice returns a new string; the original never changes.
An index points at one character, so that character has to exist. A slice is a range, and Python gives you whatever part of the range exists, even nothing:
name = "Selam"
print(name[1:100])
print(name[-3:])
print(repr(name[10:]))In the editor, press Escape then Tab to move on.
name[-3:] is the last three characters. name[10:] starts past the end, so it's the
,
''. That's why repr is there: print alone would show a blank line.
Positions must be whole numbers, which bites when you cut a string in half:
Steps, and reversing
A slice can have a third number. Predict this, with both numbers left out and a -1
at the end:
What will this print?
Decide before you look. Guessing wrong is how this sticks.
print("Selam"[::-1])Python prints
maleS
The third number is the step. -1 walks backwards, one character at a time, from the end to the start: the whole string reversed.
If you said m, you read it as [-1], the last character. If you said Sela, you read
it as [:-1], a stop of -1: everything before the last character. Count the colons:
two of them means the -1 is a third number.
The third number is the
:
how far to move each time. [::2] takes every second character, from the start.
name = "Selam"
print(name[::2])
print(name[1::2])
print(name[::-1])In the editor, press Escape then Tab to move on.
Change name to your own name and run it again.
Quick check
What is "Mawj"[::-1]?
A word that reads the same both ways is a palindrome. With [::-1], checking one is a
single comparison (and lower() from lesson 6.1, so the capital H doesn't count):
def is_palindrome(word):
word = word.lower()
return word == word[::-1]
print(is_palindrome("level"))
print(is_palindrome("Hannah"))
print(is_palindrome("Selam"))In the editor, press Escape then Tab to move on.
Cutting a piece out of a message
Here's a made-up payment message. The amount sits between ETB and the next space.
You don't know its position in advance, so find gets it for you. find takes a
second argument, the position to start searching from, which finds "the next space
after the amount". Step through it:
Step through it
Press Next to run one line at a time and watch each name change.Each row is one step: the line that just ran, and every name's value after it.
| Name | Value after line 1 |
|---|---|
| sms | 'Paid ETB 250.00 to Selam Coffee'new |
| start | not made yet |
| end | not made yet |
| amount | not made yet |
Output so far
Step 1 of 5
Step 1 of 5. Line 1: sms = "Paid ETB 250.00 to Selam Coffee". sms is now 'Paid ETB 250.00 to Selam Coffee'.
| Step | Line | sms | start | end | amount | Printed |
|---|---|---|---|---|---|---|
| 1 | 1 | 'Paid ETB 250.00 to Selam Coffee' | not made yet | not made yet | not made yet | |
| 2 | 2 | 'Paid ETB 250.00 to Selam Coffee' | 9 | not made yet | not made yet | |
| 3 | 3 | 'Paid ETB 250.00 to Selam Coffee' | 9 | 15 | not made yet | |
| 4 | 4 | 'Paid ETB 250.00 to Selam Coffee' | 9 | 15 | '250.00' | |
| 5 | 5 | 'Paid ETB 250.00 to Selam Coffee' | 9 | 15 | '250.00' | 250.00 |
Line 2: ETB starts at 5, and it's 4 characters long, so the amount starts at 9.
Line 3: the first space from 9 on is at 15. Line 4: the slice takes positions 9 to 14.
The Mawj bot reads payment messages in much the same way.
There's a trap. If ETB isn't in the message, find returns -1, and nothing stops
the program:
Exercise
The transaction ID
Cut the transaction ID out of this made-up message. It comes after ID: and ends
at the next full stop. Use find and a slice, not the ID's position counted by hand.
DF12GH34Your code
sms = "You paid ETB 250.00 to Selam Coffee. Transaction ID: DF12GH34. Thank you."
# Find where the ID starts and ends, then sliceIn the editor, press Escape then Tab to move on.
Show a solutionHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
sms = "You paid ETB 250.00 to Selam Coffee. Transaction ID: DF12GH34. Thank you."
start = sms.find("ID: ") + 4
end = sms.find(".", start)
print(sms[start:end])Key takeaways
- A slice
text[start:stop]takes fromstartup to, not including,stop, and returns a new string. - An index must exist; a slice never raises for going past the end. It gives what's there, even
''. - The step is the third number:
[::2]takes every second character,[::-1]reverses. find(text, start)searches fromstart; with slicing, it cuts a piece out of a message. Check for-1first.