Pandas str.slice(): Extract and Validate Substrings

Use str.slice(start=None, stop=None, step=None) to extract part of each string in a Series or Index. Positions start at zero, stop is exclusive, and negative bounds count from the end. Validate the source format before using extracted fields.

Start slicing at a character position 🔝

Positions begin at zero. start=1 skips the first character. The source Series is unchanged.

import pandas as pd
df = pd.DataFrame({"NAME": ["Ravi", "Raju", "Alex"]})
print(df["NAME"].str.slice(start=1))
assert df["NAME"].str.slice(start=1).tolist() == ["avi", "aju", "lex"]

Expected output

0    avi
1    aju
2    lex
Name: NAME, dtype: str

Count positions from the end 🔝

A negative start counts from the right. start=-1 returns the last character, while start=-2 returns up to two trailing characters.

print(df["NAME"].str.slice(start=-1))
print(df["NAME"].str.slice(start=-2))
assert df["NAME"].str.slice(start=-1).tolist() == ["i", "u", "x"]

Expected output

0    i
1    u
2    x
Name: NAME, dtype: str
0    vi
1    ju
2    ex
Name: NAME, dtype: str

Stop is exclusive 🔝

stop=2 selects positions zero and one. The character at position two is excluded. Omitting start uses the beginning for a positive step.

print(df["NAME"].str.slice(stop=2))
assert df["NAME"].str.slice(stop=2).tolist() == ["Ra", "Ra", "Al"]

Expected output

0    Ra
1    Ra
2    Al
Name: NAME, dtype: str

Combine start and stop 🔝

start=1, stop=3 selects positions one and two. Bounds describe positions within each string, not DataFrame rows.

print(df["NAME"].str.slice(start=1, stop=3))
assert df["NAME"].str.slice(start=1, stop=3).tolist() == ["av", "aj", "le"]

Expected output

0    av
1    aj
2    le
Name: NAME, dtype: str

Select every second character 🔝

A positive step specifies the interval between selected positions. step=2 starts at zero by default.

print(df["NAME"].str.slice(step=2))
assert df["NAME"].str.slice(step=2).tolist() == ["Rv", "Rj", "Ae"]

Expected output

0    Rv
1    Rj
2    Ae
Name: NAME, dtype: str

Use start, stop and step together 🔝

The stop remains exclusive even when a step is supplied. Strings shorter than the stop are sliced only as far as their length.

names = pd.Series(["RaviKing", "RajuQueen", "AlexMinister"])
print(names.str.slice(start=1, stop=10, step=2))
assert names.str.slice(start=1, stop=10, step=2).tolist() == ["aiig", "auue", "lxiit"]

Expected output

0     aiig
1     auue
2    lxiit
dtype: str

Compare slice() with str bracket notation 🔝

s.str[1:3] is shorthand for character slicing. s.iloc[1:3] selects Series rows instead. Bracket indexing is not a function call; see iloc row selection.

s = pd.Series(["Ravi", "Raju", "Alex"], index=[10, 20, 30], dtype="string")
print(s.str[1:3])
print("Rows selected with iloc:")
print(s.iloc[1:3])
assert s.str[1:3].equals(s.str.slice(1, 3))

Expected output

10    av
20    aj
30    le
dtype: string
Rows selected with iloc:
20    Raju
30    Alex
dtype: string

Reverse text with a negative step 🔝

step=-1 reverses the character sequence when bounds are omitted. A zero step is invalid. Reversing a displayed word is a demonstration, not a general cleaning rule.

s = pd.Series(["ABC123", "pen", ""], dtype="string")
print(s.str.slice(step=-1))
assert s.str.slice(step=-1).tolist() == ["321CBA", "nep", ""]

Expected output

0    321CBA
1       nep
2          
dtype: string

Handle missing values, blanks and short strings 🔝

Slicing preserves missing text. Out-of-range bounds produce shorter or empty strings rather than confirming valid input. Use str.len() when the source must have a required length.

s = pd.Series(["AB1234", "A", "", None], dtype="string")
result = s.str.slice(start=2, stop=6)
print(result)
assert result.iloc[:3].tolist() == ["1234", "", ""]
assert pd.isna(result.iloc[3])

Expected output

0    1234
1        
2        
3    <NA>
dtype: string

Choose a policy for numeric input 🔝

Mixed object input is not reliable text data. Converting with astype("string") preserves missing entries and turns numbers into text deliberately. It cannot restore leading zeros already lost during numeric import. See type conversion.

s = pd.Series(["0012", 1234, None], dtype="object")
text = s.astype("string")
print(text.str.slice(stop=2))
assert text.str.slice(stop=2).iloc[:2].tolist() == ["00", "12"]

Expected output

0      00
1      12
2    <NA>
dtype: string

Practical workflow: validate a fixed-format product code 🔝

This synthetic schema requires two uppercase ASCII letters followed by four digits. Trim surrounding whitespace, validate the entire value and then extract fields. Slicing alone would accept partial or malformed codes. Keep rejected values for review.

raw = pd.DataFrame({"code": [" AB0012 ", "CD0456", "A123", "EF12X4", None, "GH0070extra"]})
code = raw["code"].astype("string").str.strip()
valid = code.str.fullmatch(r"[A-Z]{2}[0-9]{4}", na=False)
accepted = raw.loc[valid].copy()
accepted["code"] = code.loc[valid]
accepted["category"] = accepted["code"].str.slice(stop=2)
accepted["item_id"] = accepted["code"].str.slice(start=2, stop=6)
print(accepted)
print("Review rows:")
print(raw.loc[~valid])
assert accepted["item_id"].tolist() == ["0012", "0456"]

Expected output

     code category item_id
0  AB0012       AB    0012
1  CD0456       CD    0456
Review rows:
          code
2         A123
3       EF12X4
4          NaN
5  GH0070extra

Check extracted fields before export 🔝

Keep identifiers as text so their leading zeros remain intact. The checks below verify the schema after extraction. For delimiter-separated fields, prefer str.split(). For matching text, see str.contains().

assert accepted["category"].str.len().eq(2).all()
assert accepted["item_id"].str.len().eq(4).all()
assert (accepted["category"] + accepted["item_id"]).equals(accepted["code"])
print(accepted.to_csv(index=False).rstrip())
# Optional Colab file export:
# accepted.to_csv("validated_code_fields.csv", index=False)

Expected output

code,category,item_id
AB0012,AB,0012
CD0456,CD,0456

Slice string labels in an Index 🔝

String slicing also works on an Index. If the result will become a key or column label, check uniqueness because shortening labels may create collisions.

labels = pd.Index(["AB0012", "AB0456", "CD0070"], name="product")
prefixes = labels.str.slice(stop=2)
print(prefixes)
print("Prefixes unique:", prefixes.is_unique)
assert not prefixes.is_unique

Expected output

Index(['AB', 'AB', 'CD'], dtype='str', name='product')
Prefixes unique: False

Choose the right extraction method 🔝

Use character slicing when positions are defined by the data specification. Use split() when delimiters define fields, and regex extraction when structure varies. For dates, use to_datetime() rather than assuming a fixed displayed date format. String positions are not UTF-8 byte offsets; combining characters can make displayed-character boundaries differ from simple slicing. Preserve readable names and international text.

Common questions 🔝

Why is the final character missing? stop is exclusive. Why did I get an empty string? Check source length, bounds and step direction. Does slicing edit my column? No; assign the result explicitly if desired. Can every row have different bounds? This method takes shared bounds; use a deliberate per-row approach for variable offsets. Is str.slice() the same as iloc? No; one slices text and the other selects rows by position.

Exercise: validate and extract a suffix 🔝

Create codes ORD-0012, ORD-0456, bad and a missing value. Require ORD- followed by exactly four digits. Extract the four-digit identifier and retain invalid rows for review. Expect two accepted codes.

Exercise solution 🔝

Check the full format before extracting a suffix. The last four characters alone would not prove a valid prefix.

orders = pd.DataFrame({"code": pd.Series(["ORD-0012", "ORD-0456", "bad", None], dtype="string")})
valid_order = orders["code"].str.fullmatch(r"ORD-[0-9]{4}", na=False)
answer = orders.loc[valid_order].copy()
answer["id"] = answer["code"].str.slice(start=-4)
print(answer)
print("Review rows:", int((~valid_order).sum()))
assert answer["id"].tolist() == ["0012", "0456"]

Expected output

       code    id
0  ORD-0012  0012
1  ORD-0456  0456
Review rows: 2

Practice in Google Colab 🔝

Open in Google Colab View on GitHub
Run the examples in order, change slice bounds and sample codes, then compare extracted values and review rows. Save your own copy to keep edits. All sample tables are included in the notebook.

Continue with the Data Cleaning and String Operations hub, string length, splitting text and combining strings.

Reference: Pandas Series.str.slice documentation.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer