Use str.len() to measure each string in a Pandas column. Inspect missing values, decide whether whitespace should count, and apply explicit length rules when checking product labels or other text fields.
str.len() measures each string separately and preserves missing entries. It does not count the rows in a DataFrame. Spaces and punctuation count as characters.
import pandas as pd
def student_data():
return pd.DataFrame({
"NAME": ["Ravi", "Raju", "Alex", "Ron", "King", "Jack"],
"ID": [1, 2, 3, 4, 5, 6],
"MATH": [80, 40, 70, 70, 70, 30],
"ENGLISH": [80, 70, 40, 50, 60, 30]
})
df = student_data()
print(df["NAME"].str.len())
assert df["NAME"].str.len().tolist() == [4, 4, 4, 3, 4, 4]Expected output
0 4
1 4
2 4
3 3
4 4
5 4
Name: NAME, dtype: int64The returned Series is aligned with the original row index, so it can be assigned to a new column.
df = student_data()
df["LENGTH"] = df["NAME"].str.len()
print(df)Expected output
NAME ID MATH ENGLISH LENGTH
0 Ravi 1 80 80 4
1 Raju 2 40 70 4
2 Alex 3 70 40 4
3 Ron 4 70 50 3
4 King 5 70 60 4
5 Jack 6 30 30 4Numeric values do not have string length until converted. This measures the displayed text representation, not storage size. Negative signs count too. Preserve identifiers as strings when leading zeros matter; astype() explains conversion choices.
df = student_data()
df["LENGTH"] = df["ENGLISH"].astype(str).str.len()
print(df)
extra = pd.Series([0, -12, 100], dtype="int64")
print(extra.astype("string").str.len().tolist())
assert df["LENGTH"].eq(2).all()Expected output
NAME ID MATH ENGLISH LENGTH
0 Ravi 1 80 80 2
1 Raju 2 40 70 2
2 Alex 3 70 40 2
3 Ron 4 70 50 2
4 King 5 70 60 2
5 Jack 6 30 30 2
[1, 3, 3]Casting floats to strings measures Python’s resulting representation. Trailing zeros may be removed and scientific notation may appear. It cannot recover the original number of decimal places typed in a source file.
df = student_data()
df["MATH"] = [80.34, 40.21, 70.456, 70.123, 70.0, 30.9]
df["LENGTH"] = df["MATH"].astype(str).str.len()
print(df)
assert df["LENGTH"].tolist() == [5, 5, 6, 6, 4, 4]Expected output
NAME ID MATH ENGLISH LENGTH
0 Ravi 1 80.340 80 5
1 Raju 2 40.210 70 5
2 Alex 3 70.456 40 6
3 Ron 4 70.123 50 6
4 King 5 70.000 60 4
5 Jack 6 30.900 30 4Define formatting first when validating a display field. This example uses two decimal places. The result is a display string; retain the numeric data for calculations.
amount = pd.Series([12.5, 0.0, 1234.0])
display = amount.map(lambda value: f"{value:.2f}")
print(pd.DataFrame({"amount": amount, "display": display, "length": display.str.len()}))
assert display.str.len().tolist() == [5, 4, 7]Expected output
amount display length
0 12.5 12.50 5
1 0.0 0.00 4
2 1234.0 1234.00 7With nullable string data, a missing entry has a missing length, while an empty string has length zero. Do not fill missing lengths with zero unless the report intentionally treats unknown and empty as equivalent. See fillna().
text = pd.Series(["Alex", "", None, " "], dtype="string")
lengths = text.str.len()
print(pd.DataFrame({"text": text, "length": lengths}))
assert lengths.iloc[1] == 0
assert pd.isna(lengths.iloc[2])Expected output
text length
0 Alex 4
1 0
2 <NA> <NA>
3 2strip() removes surrounding whitespace, not interior spaces. Decide whether the raw or normalized value is subject to your length rule. Use str.replace() when repeated interior whitespace should also be normalized.
text = pd.Series([" Alex ", "Blue pen", " ", None], dtype="string")
trimmed = text.str.strip()
print(pd.DataFrame({"raw": text, "raw_length": text.str.len(), "trimmed": trimmed, "trimmed_length": trimmed.str.len()}))
assert trimmed.str.len().iloc[0] == 4Expected output
raw raw_length trimmed trimmed_length
0 Alex 7 Alex 4
1 Blue pen 8 Blue pen 8
2 3 0
3 <NA> <NA> <NA> <NA>A nullable comparison can produce missing Boolean values. fillna(False) explicitly excludes missing text from the match. Combine length rules with text matching where needed.
df = pd.DataFrame({"name": pd.Series(["Alex", "Ron", None, "Ravi"], dtype="string")})
mask = df["name"].str.len().eq(4).fillna(False)
print(df.loc[mask])
assert df.loc[mask, "name"].tolist() == ["Alex", "Ravi"]Expected output
name
0 Alex
3 RaviOn a mixed object Series, str.len() can return missing for numeric values and lengths for list values. If the field must be text, detect unexpected types rather than silently converting every value. dtypes alone does not describe every Python value.
mixed = pd.Series(["pen", 123, ["red", "blue"], None], dtype="object")
print("Direct lengths:")
print(mixed.str.len())
unexpected = mixed.notna() & ~mixed.map(lambda value: isinstance(value, str))
print("Unexpected types:", mixed.loc[unexpected].map(lambda value: type(value).__name__).tolist())
assert unexpected.sum() == 2Expected output
Direct lengths:
0 3.0
1 NaN
2 2.0
3 NaN
dtype: float64
Unexpected types: ['int', 'list']str.len() counts Unicode code points, not encoded bytes or user-perceived grapheme clusters. A combining accent can occupy an additional code point. Normalize to NFC when that is appropriate, and measure encoded bytes separately if a byte limit is the actual requirement.
text = pd.Series(["é", "e\u0301", "pen"], dtype="string")
normalized = text.str.normalize("NFC")
print("Code-point lengths:", text.str.len().tolist())
print("NFC lengths:", normalized.str.len().tolist())
print("UTF-8 bytes:", text.str.encode("utf-8").str.len().tolist())
assert text.str.len().tolist() == [1, 2, 3]
assert normalized.str.len().tolist() == [1, 1, 3]Expected output
Code-point lengths: [1, 2, 3]
NFC lengths: [1, 1, 3]
UTF-8 bytes: [2, 3, 3]len(df) counts rows, count() counts non-missing observations, and str.len() measures each string. These answer different questions; see count().
df = pd.DataFrame({"name": pd.Series(["Alex", "Ron", None], dtype="string")})
print("Rows:", len(df))
print("Known names:", df["name"].count())
print("Individual lengths:", df["name"].str.len().tolist())
assert len(df) == 3 and df["name"].count() == 2Expected output
Rows: 3
Known names: 2
Individual lengths: [4, 3, <NA>]This synthetic product table uses a demonstration rule of 1 to 20 code points after trimming. Keep raw labels and flag missing, blank and overlong values separately. A length check does not prove that a product description is accurate.
products = pd.DataFrame({
"code": ["0012", "0045", "0070", "0081", "0099"],
"label": [" Notebook A5 ", "Pen", " ", None, "Extra large notebook pack"]
})
products["clean_label"] = products["label"].astype("string").str.strip()
products["length"] = products["clean_label"].str.len()
missing = products["clean_label"].isna()
blank = products["length"].eq(0).fillna(False)
too_long = products["length"].gt(20).fillna(False)
valid = products["length"].between(1, 20).fillna(False)
print(products)
print("Accepted codes:", products.loc[valid, "code"].tolist())
assert products.loc[valid, "code"].tolist() == ["0012", "0045"]Expected output
code label clean_label length
0 0012 Notebook A5 Notebook A5 11
1 0045 Pen Pen 3
2 0070 0
3 0081 NaN <NA> <NA>
4 0099 Extra large notebook pack Extra large notebook pack 25
Accepted codes: ['0012', '0045']Review failed labels instead of automatically truncating them. Truncation can remove distinguishing details or create duplicate labels. slicing is useful for intentional display shortening, while Excel export can carry accepted and review tables.
print("Missing:", missing.sum())
print("Blank:", blank.sum())
print("Too long:", too_long.sum())
accepted = products.loc[valid, ["code", "clean_label"]].copy()
review = products.loc[~valid].copy()
print("Review rows:")
print(review)
assert len(accepted) + len(review) == len(products)
# Optional Colab exports:
# accepted.to_csv("accepted_product_labels.csv", index=False)
# review.to_csv("product_labels_for_review.csv", index=False)Expected output
Missing: 1
Blank: 1
Too long: 1
Review rows:
code label clean_label length
2 0070 0
3 0081 NaN <NA> <NA>
4 0099 Extra large notebook pack Extra large notebook pack 25Why does the string accessor fail? Inspect a purely numeric column and convert deliberately if text representation is intended. Why is a missing value not length zero? Its length is unknown; zero describes an empty value. Why do visually identical strings have different lengths? Unicode composition can differ. Can I validate an email with length alone? No; length is only one constraint. Why does a list have length two? str.len() can also measure list-like elements. For other text operations, explore case conversion and splitting.
Create labels " pen ", "Notebook", "", None and "Pencil". Trim surrounding spaces and select lengths between three and six inclusive. Expect pen and Pencil; retain missing values separately for review.
Trim first, then explicitly treat missing comparisons as non-matches.
labels = pd.Series([" pen ", "Notebook", "", None, "Pencil"], dtype="string")
clean = labels.str.strip()
mask = clean.str.len().between(3, 6).fillna(False)
print(clean.loc[mask].tolist())
print("Missing labels:", clean.isna().sum())
assert clean.loc[mask].tolist() == ["pen", "Pencil"]Expected output
['pen', 'Pencil']
Missing labels: 1Open in Google Colab View on GitHub
Run the examples in order, change text labels and length limits, then compare accepted and review rows. Save your own copy to keep edits. All sample tables are included in the notebook.
Continue with data cleaning, str.contains() and str.replace().
Reference: Pandas Series.str.len documentation.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.