Skip to main content

Module casing

Module casing 

Source
Expand description

Changing the case of a string, which is six questions rather than one.

upper and lower are the two that look easy, and even those are not a per-character mapping: 'ß'.upper() is two characters and 'Σ'.lower() is one of two characters depending on what is around it. The other four are each different again. title has to know where a word starts, capitalize uses a third mapping that is neither of the first two, swapcase picks per character, and casefold is a mapping of its own that disagrees with lower on a few hundred code points.

The data all of that needs is in the table module next door, generated from the CPython whose answers we are matching. Rust’s standard library has some of it and is not used, because it carries its own copy of the Unicode data and the two are not always the same release.

§The final sigma

Greek writes a lowercase sigma as ς at the end of a word and σ everywhere else, and the uppercase is Σ either way, so lowercasing a sigma is the one decision here that is not a fact about the code point. The rule is that the final form is used when there is a cased character before the sigma and none after it, looking past case-ignorable characters in both directions.

It matters that the scan reads the original string and not the output. In 'ΑΣΣ' the first sigma is followed by a cased character and the second is not, so the answer is 'ασς', and a runtime that lowercased left to right while looking at what it had already written would get the first one wrong. Four of the six methods lowercase something, and all four take their context from the input.

Functions§

capitalize
str.capitalize, which is title that stops looking for words after the first character.
casefold
str.casefold, which is for comparing rather than for displaying.
is_cased
Whether cp is cased at all, which is what decides where title sees a word start and is wider than the three above put together.
is_lowercase
Whether cp is lowercase, which is the Lowercase property and so is wider than the Ll category: a modifier letter such as ʰ is in it.
is_titlecase
Whether cp is titlecase, which is neither of the other two.
is_uppercase
Whether cp is uppercase.
lower
str.lower.
swapcase
str.swapcase.
title
str.title.
upper
str.upper.