Skip to content
VLSI Mentor

Python Part I · Module 4 · Strings

Slicing: Taking Part of a String

Indexing gets you one character. Far more often you want a run of them — the first nine characters of a log line, the field sitting between columns twelve and sixteen, everything after a known prefix. Python's notation for that is slicing, and it is simple once you see the idea underneath it: the numbers in a slice do not name characters, they name the boundaries between characters. Get that and the rule everyone else memorises — that the stop value is excluded — stops being arbitrary and becomes the only thing it could sensibly mean. This chapter builds the notation one field at a time, and shows the one place slicing behaves completely differently from indexing.

Foundation14 min readPythonPart IFundamentalsStringsSlicing

Part I · Module 4 · Chapter 4.5 · Slicing: Taking Part of a String

1. Asking for a Run of Characters

Chapter 4.4 gave you one character at a time. That is rarely what a real question needs. Given this line, the interesting part is the severity word at the front — nine characters, not one:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
line = "UVM_ERROR @ 1200 ns"

You could reach line[0], line[1], line[2] and glue them together, and it would be miserable. Python has notation for the whole run: two numbers inside the square brackets, separated by a colon.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[0:3])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi

name[0:3] is a slice. Read it as "from boundary 0 up to boundary 3". It gave back three characters — a, x, i — and it did not include the character at position 3, which is the underscore.

That last point is the one everything else in this chapter depends on, so the next section explains why it works that way rather than asking you to remember it.

2. The Numbers Name Boundaries, Not Characters

Here is the picture that makes slicing obvious. The numbers sit on the walls between the characters, not on the characters themselves:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  boundary   0   1   2   3   4   5   6   7   8   9
             +---+---+---+---+---+---+---+---+---+
  "axi_smoke"| a | x | i | _ | s | m | o | k | e |
             +---+---+---+---+---+---+---+---+---+

A nine-character string has ten boundaries — one before the first character, one after the last, and eight in between. A slice names two of those boundaries and gives you everything between them.

So name[0:3] means "start at wall 0, stop at wall 3", and the characters lying between those two walls are a, x, i. The underscore is on the far side of wall 3. Nothing was excluded by a special rule; it was simply not between the two walls you named.

Two useful facts come free from the wall model, and neither needs memorising.

The length of a slice is stop - start.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(len(name[0:3]))
print(len(name[2:7]), 7 - 2)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3
5 5

Wall 2 to wall 7 spans five cells, so the slice has five characters. If the numbers had named characters inclusively you would be subtracting and adding one forever.

Adjacent slices tile exactly — no gap, no overlap, nothing lost:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[0:3], "|", name[3:9])
print(name[0:3] + name[3:9] == name)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi | _smoke
True

The first slice stops at wall 3 and the second starts at wall 3, and together they reconstruct the original string exactly. That is the property that makes slicing safe for splitting fixed-width data, and it would be impossible if stop were included — the character at position 3 would appear in both.

3. Leaving a Boundary Out

Very often one of the two boundaries is just "the end of the string" or "the beginning". Python lets you omit it rather than compute it.

Omit the start and the slice begins at the beginning:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[:3])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi

Omit the stop and the slice runs to the end:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[4:])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke

This is the form you will write most, because "everything from here on" is an extremely common need and the alternative is name[4:len(name)], which says the same thing with more noise.

Omit both and you get the whole string:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[:])
print(name[:] == name)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi_smoke
True

name[:] is a complete slice from wall 0 to the last wall. For strings this is not a very useful thing to write — it produces a value equal to the one you started with — but you will see it in other people's code and now it will not puzzle you.

Now the canonical example from the curriculum. Both fields come out of one line with one omitted boundary each:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
line = "UVM_ERROR @ 1200 ns"
print(line[:9])
print(line[12:16])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
UVM_ERROR
1200

line[:9] is the first nine characters — the severity. line[12:16] is the four characters starting at wall 12, which is the timestamp. Count the walls on the printed line if you want to check: U is at 0, so the space after UVM_ERROR is at 9, @ at 10, space at 11, and 1200 occupies cells 12 through 15 — which is exactly walls 12 to 16.

4. A Slice Is a String

Nothing exotic comes back:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(type(name[0:3]))
print(len(name[0:3]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<class 'str'>
3

A slice of a string is a string, so everything you already know works on it — comparison, concatenation, membership, further slicing.

There is one small place slicing and indexing differ visibly. A one-character slice and an index produce the same value here:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[0])
print(name[0:1])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a
a

Both are the one-character string "a". The difference is in what happens when you ask for something that is not there, which is the next section.

5. An Out-of-Range Slice Does Not Fail

This is the genuinely surprising part of the chapter, and it is worth meeting deliberately because it cuts both ways.

Recall from Chapter 4.4 that an index past the end raises:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
name = "axi_smoke"
print(name[9])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
IndexError: string index out of range

A slice past the end does not raise. It quietly gives you as much as exists:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[0:100])
print(name[5:100])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi_smoke
moke

No error, no warning. Python treats a boundary beyond the end of the string as meaning "the end of the string".

Push it further and you get an empty string rather than a complaint:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(repr(name[100:200]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
''

repr() is used here only so you can see the empty result — it shows a value the way you would write it in source, which is how we can tell an empty string apart from a blank line of output.

The same tolerance applies when the boundaries are in the wrong order, or identical:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(repr(name[5:2]))
print(repr(name[3:3]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
''
''

Wall 5 to wall 2 encloses nothing, so the slice is empty. Wall 3 to wall 3 is the same wall twice, which also encloses nothing.

6. Negative Boundaries

The negative numbering from Chapter 4.4 works in slices too, and it counts from the end in exactly the same way:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "axi_smoke"
print(name[-5:])
print(name[:-6])
print(name[-5:-2])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke
axi
smo

name[-5:] is "the last five characters". That is a genuinely useful idiom — it gets you the tail of a string without knowing its length.

name[:-6] is "everything except the last six characters". Read it as cutting off the end rather than counting from the front, which is how it is meant.

name[-5:-2] mixes two negative walls: start five from the end, stop two from the end, giving three characters. The arithmetic still works — (-2) - (-5) is 3.

7. Two Things Slicing Is Actually For

Trimming a known prefix

When a line begins with a fixed marker, slicing past it gives you the remainder:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
full = "UVM_ERROR: scoreboard mismatch"
print(full[len("UVM_ERROR: "):])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
scoreboard mismatch

The slice starts at wall len("UVM_ERROR: "), which is 11 — the width of the marker including its colon and space. Writing it as len("UVM_ERROR: ") rather than 11 is deliberate: the number is derived from the marker itself, so if the marker changes the slice follows. That is the same habit as the underline in Chapter 4.3.

Chapter 4.7 introduces removeprefix, which says this more directly. Slicing is worth seeing first, because it is the mechanism underneath.

Pulling fixed-width fields

Some tool output is laid out in columns of fixed width. Slicing tiles it apart:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
row = "axi_smoke   PASS   182.4"
print(repr(row[0:12]))
print(repr(row[12:19]))
print(repr(row[19:]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
'axi_smoke   '
'PASS   '
'182.4'

Three adjacent slices, three fields, and the padding spaces come along with them — which is why repr() is used to show them. Chapter 4.7 removes that padding and Chapter 4.8 offers a better approach for output that is separated rather than aligned.

8. Escapes Occupy One Cell

As in Chapter 4.4, an escape sequence is one character and so occupies one cell:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
e = "PASS\nFAIL"
print(repr(e[:4]))
print(repr(e[4:5]))
print(repr(e[5:]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
'PASS'
'\n'
'FAIL'

Nine cells, and cell 4 is the newline. If you had counted \n as two characters, every boundary after it would be off by one.

9. The Third Field

You may see a slice elsewhere with two colons, such as text[::2]. That third field is a step, and it is not needed for anything in this course. It is named here only so that you recognise it rather than misread it as a typo.

10. Predict, Run, Observe

Given line = "UVM_ERROR @ 1200 ns", predict all six before reading on:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
line = "UVM_ERROR @ 1200 ns"
print(line[0:3])
print(line[:9])
print(line[10:11])
print(line[-2:])
print(repr(line[9:10]))
print(repr(line[16:12]))

The verified output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
UVM
UVM_ERROR
@
ns
' '
''

The fifth is a single space — wall 9 to wall 10 encloses the one space character between UVM_ERROR and @, and repr() is the only reason you can see it. The sixth is empty because the boundaries are reversed: wall 16 to wall 12 encloses nothing, and Python does not object.

If you predicted an error for the last one, you were carrying the indexing rule over to slices. Section 5 is the correction.

11. Exercises

Exercise 1 — read the ruler. For word = "RESET_N", give the result of each without running it, then check: [0:5], [:5], [5:], [6:7], [-2:], [:-2].

Exercise 2 — the length shortcut. Without running anything, say how many characters each of these produces: text[3:8], text[0:1], text[4:4], text[2:9]. Then say which one you cannot answer without knowing the string, and why.

Exercise 3 — tile it. For path = "sim.log", write two slices that together reconstruct the whole string, splitting it at the dot so that the dot belongs to the second piece. Verify by concatenating them and comparing against path.

Exercise 4 — trim the prefix. Given entry = "WARNING: setup violation", produce setup violation using a slice whose boundary is derived from the marker rather than typed as a number.

Exercise 5 — the silent empty. Explain in two sentences why name[5:2] gives an empty string while name[50] raises an IndexError, and say which behaviour you would rather have when debugging.

Exercise 6 — fixed-width columns. The row "reg_rw FAIL 91.2" has a 12-character name column, a 7-character status column, and the rest is the runtime. Write three slices that extract the three fields, and say what is still wrong with the two you extracted before Chapter 4.7 cleans them up.

Exercise 7 — count the escape. For two = "A\tB", predict len(two), two[1:2], and two[2:]. Explain the length in terms of Chapter 4.2.

12. Summary

  • text[start:stop] takes the characters between two boundaries. The numbers name the walls between characters, not the characters themselves.
  • Start is included and stop is excluded — because the character after the stop wall is on the other side of it.
  • A slice's length is stop - start, and adjacent slices tile exactly. Both follow from the wall model rather than needing to be remembered.
  • Omit the start for "from the beginning", the stop for "to the end", both for a full copy.
  • A slice of a string is a string. text[0] and text[0:1] produce the same one-character value.
  • An out-of-range slice does not raise — unlike an out-of-range index. It gives you as much as exists, or an empty string. Convenient, and a silent bug when a boundary is wrong.
  • Reversed or identical boundaries give an empty string, not an error.
  • Negative boundaries count from the end. text[:n] is the first n characters; text[-n:] is the last n.
  • Derive boundaries where you can — full[len(marker):] survives a change to the marker; full[11:] does not.
  • Fixed-width slicing only works on genuinely fixed columns. For separated text, Chapter 4.8 has the right tool.

You can now reach into a string. The next chapter steps back out and asks two questions about the whole of it.

Where this fits

Part of the Python curriculum.