The str.casefold() method returns a casefolded copy of the string, implementing the aggressive full case-folding algorithm defined in Section 3.13 of the Unicode Standard. While similar to str.lower() for standard ASCII English text, casefold() converts complex international characters so that case-insensitive comparisons succeed across global languages.
The German ß Benchmark: In German, lowercase "ß" (Eszett / sharp S) has an uppercase equivalent of "SS". Calling "ß".lower() leaves it unchanged as "ß", causing comparisons against "SS".lower() to fail. In contrast, "ß".casefold() expands to "ss", ensuring exact caseless equivalence.
The casefold() method takes no arguments and returns a newly transformed string:
folded_string = string.casefold()
| Parameter | Type | Description |
|---|---|---|
| None | — | Takes zero arguments. Passing parameters raises TypeError. |
| Return Value | str |
Returns a new string where all characters are converted to their Unicode casefolded equivalents. |
For standard ASCII English text (letters A–Z), casefold() behaves identically to str.lower():
headline = "Welcome To Plus2Net Python Tutorial"
print(headline.casefold())
# Case-insensitive equality check
user_input = "PYTHON"
stored_val = "python"
if user_input.casefold() == stored_val.casefold():
print("Strings match caselessly!")
Output:
welcome to plus2net python tutorial
Strings match caselessly!
The crucial distinction between lower() and casefold() emerges when dealing with multi-byte international alphabets where lowercase conversion is not a simple 1:1 mapping:
german_word = "Straße" # German word for 'Street'
uppercase_german = "STRASSE"
# 1. Comparison using str.lower() FAILS:
print("lower():", german_word.lower()) # 'straße' (ß unchanged)
print("lower() match:", german_word.lower() == uppercase_german.lower()) # False!
# 2. Comparison using str.casefold() SUCCEEDS:
print("casefold():", german_word.casefold()) # 'strasse' (ß expands to 'ss')
print("casefold() match:", german_word.casefold() == uppercase_german.casefold()) # True!
Output:
lower(): straße
lower() match: False
casefold(): strasse
casefold() match: True
"ß" is already a lowercase letter in Unicode, "ß".lower() does nothing. However, German uppercase rules historically mapped "ß" to "SS". Full case folding recognizes this equivalence by expanding "ß" into "ss".
Unicode case folding addresses unique script behaviors across multiple world languages:
# 1. Greek Sigma: final sigma 'ς' vs middle sigma 'σ' (uppercase 'Σ')
greek_title = "Τεχνολογία"
greek_lower = "τεχνολογία"
print("Greek match:", greek_title.casefold() == greek_lower.casefold()) # True
# Both forms of lowercase Greek sigma fold to middle sigma 'σ'
print("final sigma: ", "ς".casefold()) # 'σ'
print("middle sigma:", "σ".casefold()) # 'σ'
# 2. Capital Sharp S (ẞ / \u1e9e) introduced in recent German orthography
print("Capital Eszett:", "ẞ".casefold()) # 'ss'
# 3. Cherokee case folding (Unicode 8.0 uppercase/lowercase pairs)
cherokee_text = "Ꮰ"
print("Cherokee folded:", cherokee_text.casefold())
Output:
Greek match: True
final sigma: σ
middle sigma: σ
Capital Eszett: ss
Cherokee folded: Ꮰ
In Unicode, characters can be expressed as single precomposed codepoints (e.g. 'é' as é) or decomposed sequences (e.g. 'e' + '́'). For complete multi-lingual comparison fidelity, pairing unicodedata.normalize('NFC', text) with casefold() guarantees identical binary representations:
import unicodedata
str_composed = "café" # Precomposed e with acute
str_decomposed = "cafe\u0301" # Decomposed 'e' + combining acute accent
# Direct equality without normalization might fail if byte sequences differ:
norm1 = unicodedata.normalize('NFC', str_composed).casefold()
norm2 = unicodedata.normalize('NFC', str_decomposed).casefold()
print("Normalized caseless match:", norm1 == norm2) # True
Output:
Normalized caseless match: True
In Python 3, re.search(pattern, text, re.IGNORECASE) uses full Unicode matching rules by default. However, executing casefold() directly in Python avoids the computational overhead of compiling and executing a regex engine for simple substring containment:
import re
haystack = "Besuchen Sie die Friedrichstraße in Berlin."
needle = "STRASSE"
# Approach 1: Python casefold substring check (fastest for simple substrings)
match_cf = needle.casefold() in haystack.casefold()
# Approach 2: Regular expression with IGNORECASE
match_re = bool(re.search(re.escape(needle), haystack, re.IGNORECASE))
print("casefold match:", match_cf) # True
print("regex match: ", match_re) # True
Output:
casefold match: True
regex match: True
The table below summarizes how Python casing functions transform challenging characters:
| Original Input | str.lower() |
str.casefold() |
str.upper() |
str.title() |
|---|---|---|---|---|
"Hello" | "hello" | "hello" | "HELLO" | "Hello" |
"Straße" | "straße" | "strasse" | "STRASSE" | "Strasse" |
"ß" | "ß" | "ss" | "SS" | "Ss" |
"Σ" (Greek Sigma) | "σ" | "σ" | "Σ" | "Σ" |
"ς" (Final Sigma) | "ς" | "σ" | "Σ" | "Σ" |
"123" | "123" | "123" | "123" | "123" |
When searching user queries against blog articles or product catalogs, using casefold() ensures German, Greek, and Latin variations match seamlessly:
def caseless_contains(haystack, needle):
return needle.casefold() in haystack.casefold()
document = "Wir wohnen in der Goethestraße in München."
print("Search 'STRASSE': ", caseless_contains(document, "STRASSE")) # True
print("Search 'GOETHE': ", caseless_contains(document, "goethe")) # True
print("Search 'BERLIN': ", caseless_contains(document, "berlin")) # False
Output:
Search 'STRASSE': True
Search 'GOETHE': True
Search 'BERLIN': False
Implementing HTTP header dictionaries or configuration stores where lookup keys are case-insensitive:
class CaselessDict:
def __init__(self):
self._data = {}
def __setitem__(self, key, value):
self._data[key.casefold()] = value
def __getitem__(self, key):
return self._data[key.casefold()]
def __contains__(self, key):
return key.casefold() in self._data
headers = CaselessDict()
headers["Content-Type"] = "application/json"
print("content-type lookup:", headers["content-type"]) # application/json
print("CONTENT-TYPE in map:", "CONTENT-TYPE" in headers) # True
Output:
content-type lookup: application/json
CONTENT-TYPE in map: True
The following production script implements an internationalized search index and case-insensitive lookup table with automated self-checking unit assertions:
class MultilingualSearchIndex:
def __init__(self):
self._documents = []
def add_document(self, doc_id, text):
self._documents.append({"id": doc_id, "text": text, "folded": text.casefold()})
def search(self, query):
# Performs case-folded substring matching across indexed documents
if not query:
return []
q_folded = query.casefold()
return [d["id"] for d in self._documents if q_folded in d["folded"]]
# --- Unit Assertions and Verification ---
index = MultilingualSearchIndex()
index.add_document(1, "Goethestraße Bakery, Munich")
index.add_document(2, "Greek Technology Portal: Τεχνολογία")
index.add_document(3, "Python Standard Library Documentation")
# 1. German Eszett matching: query 'strasse' matches 'Goethestraße'
assert index.search("strasse") == [1]
assert index.search("STRASSE") == [1]
assert index.search("Straße") == [1]
# 2. Greek sigma matching
assert index.search("τεχνολογία") == [2]
assert index.search("ΤΕΧΝΟΛΟΓΊΑ") == [2]
# 3. Standard English ASCII caseless matching
assert index.search("python") == [3]
assert index.search("DOCUMENTATION") == [3]
assert index.search("NonExistentTerm") == []
print("Search for 'STRASSE' matched doc IDs: ", index.search("STRASSE"))
print("Search for 'τεχνολογία' matched doc IDs:", index.search("τεχνολογία"))
print("All str.casefold() unit assertions passed successfully!")
Open in Google Colab View on GitHub
Run all case folding examples interactively, benchmark German sharp S and Greek sigma transformations, evaluate caseless dictionary implementations, and build international search indexes in Google Colab.
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.