str.casefold()

The correct tool for case-insensitive string comparison — where lower() falls short on non-Latin scripts.

String methodPython 3.3+Live demo
Common call
a.casefold() == b.casefold()
Returns
a new str — the original is unchanged
Replaces
a.lower() == b.lower() when Unicode correctness matters
Watch out
result may be LONGER than input (ß → ss); does not normalize accents
str.casefold()
str

Demo

Live evaluation
Try:
Inputs
stringstrthe source
Output
'HELLO'.casefold()
'hello'

casefold applies the Unicode "case-folding" mapping — an aggressive lowercase designed for comparison, not display. The German ß becomes "ss" (not ß) because case-insensitive Straße should match STRASSE. lower() would leave ß unchanged, breaking the match. For any user-input comparison across languages, casefold is the correct default.

Common patterns

Case-insensitive equality
The idiomatic way — works across languages.
if a.casefold() == b.casefold():
    ...
Case-insensitive set membership
Fold both the item and the set contents.
allowed = {"gold", "silver", "bronze"}
if user_input.casefold() in {x.casefold() for x in allowed}:
    ...
Case-insensitive sort key
casefold makes an excellent key for locale-neutral sorting.
names.sort(key=str.casefold)

Examples

1. Basic
"HELLO".casefold()
Returns
"hello"
2. German ß expands
"straße".casefold()
Returns
"strasse"
3. Straße == STRASSE
"Straße".casefold() == "STRASSE".casefold()
Returns
True
4. lower() misses it
"Straße".lower() == "STRASSE".lower()
Returns
False # ß != ss
5. Accents preserved
"CAFÉ".casefold()
Returns
"café"
6. Empty is empty
"".casefold()
Returns
""

Pitfalls

1. casefold is NOT the same as lower()
lower() is a simple case mapping — one character in, one character out. casefold applies the Unicode case-folding table, which can EXPAND a character (ß → ss) or map to unusual lowercase forms.
lower() misses ß
"Straße".lower() == "STRASSE".lower()
False # ß stays ß
casefold gets it
"Straße".casefold() == "STRASSE".casefold()
True
2. Length can change
ß casefolds to two characters. A length check before and after may fail unexpectedly.
Grew by one
len("Straße".casefold())
7 # was 6
Do not assume length preservation
# treat as arbitrary string transformation
3. Does NOT normalize accents or diacritics
casefold folds case, not diacritics. "café" and "cafe" still compare unequal. For accent-insensitive matching, use unicodedata.normalize.
Still different
"café".casefold() == "cafe".casefold()
False
Normalize NFKD + strip combining
import unicodedata
def strip_accents(s):
    return "".join(c for c in unicodedata.normalize("NFKD", s)
                   if not unicodedata.combining(c))
accent-insensitive after this
4. Original string is NOT modified
Like all string methods, casefold returns a new string. Assigning it back is required for the folded value to persist.
Lost result
s = "HELLO"
s.casefold()
print(s)
"HELLO" # unchanged
Capture it
s = s.casefold()
print(s)
"hello"

When to use

Use it
  • Case-insensitive equality across any language
  • Sort keys where case should not matter
  • Building case-insensitive sets or lookups
  • Any user-input comparison where locale-neutral behavior is required
Reach for something else
  • Display formatting — lower() and upper() are for display, casefold is for comparison
  • ASCII-only text where lower() is enough and reads more idiomatically
  • Accent-insensitive matching → normalize with unicodedata first
  • Length-sensitive operations after folding

Notes

Complexity
O(n)
Return
A new string; length may exceed the original due to expansions like ß → ss
CPython impl
Objects/unicodeobject.c :: unicode_casefold — applies Unicode's CaseFolding table
Memory
Allocates one new string
Thread-safe
Yes — strings are immutable

FAQ

lower() applies Unicode's simple lowercase mapping — one code point in, one out. casefold applies the Unicode case-folding mapping, which is designed for caseless comparison and handles special cases like ß → ss and Greek final sigma. Use lower for display; use casefold for equality.

History

3.3
casefold() introduced — replacing hand-rolled Unicode-aware lowercase workarounds.