Pandas str.len(): Measure Text Length and Validate Fields

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.

Measure the length of each student name 🔝

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: int64

Store lengths in a new column 🔝

The 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       4

Measure the text representation of integers 🔝

Numeric 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]

Distinguish float formatting from source precision 🔝

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       4

Measure an explicitly formatted numeric string 🔝

Define 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       7

Keep missing text distinct from empty text 🔝

With 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             2

Compare raw and trimmed lengths 🔝

strip() 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] == 4

Expected 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>

Filter rows by length with an explicit missing policy 🔝

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  Ravi

Inspect mixed columns before converting them 🔝

On 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() == 2

Expected output

Direct lengths:
0    3.0
1    NaN
2    2.0
3    NaN
dtype: float64
Unexpected types: ['int', 'list']

Understand Unicode length and byte length 🔝

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]

Compare text length with row and value counts 🔝

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() == 2

Expected output

Rows: 3
Known names: 2
Individual lengths: [4, 3, <NA>]

Practical workflow: validate product labels 🔝

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']

Audit and export the accepted labels 🔝

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      25

Common questions and mistakes 🔝

Why 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.

Exercise: select labels of three to six characters 🔝

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.

Exercise solution 🔝

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: 1

Practice in Google Colab 🔝

Open 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.




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