Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
:c:func:`Py_UNICODE_TOUPPER`, :c:func:`Py_UNICODE_TOLOWER` and
:c:func:`Py_UNICODE_TOTITLE` now return the simple case mapping defined by the
Unicode database instead of the first character of the full case mapping. The
simple uppercase of ``'ß'`` (U+00DF) is now ``'ß'`` instead of ``'S'``, and the
simple uppercase of ``'ᾀ'`` (U+1F80) is ``'ᾈ'`` (U+1F88) instead of ``'Ἀ'``
(U+1F08).
8 changes: 6 additions & 2 deletions Modules/_sre/sre.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,8 +595,12 @@ static int
_sre_unicode_iscased_impl(PyObject *module, int character)
/*[clinic end generated code: output=9c5ddee0dc2bc258 input=51e42c3b8dddb78e]*/
{
unsigned int ch = (unsigned int)character;
return ch != sre_lower_unicode(ch) || ch != sre_upper_unicode(ch);
Py_UCS4 ch = (Py_UCS4)character;
Py_UCS4 mapped[3];
/* A cased character can have no simple case mapping, as LATIN SMALL
LETTER SHARP S whose uppercase is "SS". */
return _PyUnicode_ToUpperFull(ch, mapped) != 1 || mapped[0] != ch ||
_PyUnicode_ToLowerFull(ch, mapped) != 1 || mapped[0] != ch;
}

/*[clinic input]
Expand Down
33 changes: 30 additions & 3 deletions Objects/unicodectype.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ Py_UCS4 _PyUnicode_ToTitlecase(Py_UCS4 ch)
{
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);

if (ctype->flags & EXTENDED_CASE_MASK)
if (ctype->flags & EXTENDED_CASE_MASK) {
/* No character with a longer full titlecase has a simple one. */
if ((ctype->title >> 24) != 1)
return ch;
return _PyUnicode_ExtendedCase[ctype->title & 0xFFFF];
}
return ch + ctype->title;
}

Expand Down Expand Up @@ -182,8 +186,25 @@ Py_UCS4 _PyUnicode_ToUppercase(Py_UCS4 ch)
{
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);

if (ctype->flags & EXTENDED_CASE_MASK)
if (ctype->flags & EXTENDED_CASE_MASK) {
if ((ctype->upper >> 24) != 1) {
/* Only the full mapping is stored when it is longer than one
character (see Tools/unicode/makeunicodedata.py). Most such
characters have no simple uppercase, but the Greek letters
with ypogegrammeni have the one with prosgegrammeni. All of
them are Unicode 1.1. */
if (ch >= 0x1F80 && ch <= 0x1FA7 && !(ch & 8)) {
return ch + 8;
}
switch (ch) {
case 0x1FB3: return 0x1FBC; /* ALPHA WITH YPOGEGRAMMENI */
case 0x1FC3: return 0x1FCC; /* ETA WITH YPOGEGRAMMENI */
case 0x1FF3: return 0x1FFC; /* OMEGA WITH YPOGEGRAMMENI */
}
return ch;
}
return _PyUnicode_ExtendedCase[ctype->upper & 0xFFFF];
}
return ch + ctype->upper;
}

Expand All @@ -194,8 +215,14 @@ Py_UCS4 _PyUnicode_ToLowercase(Py_UCS4 ch)
{
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);

if (ctype->flags & EXTENDED_CASE_MASK)
if (ctype->flags & EXTENDED_CASE_MASK) {
if ((ctype->lower >> 24) != 1) {
/* LATIN CAPITAL LETTER I WITH DOT ABOVE is the only character
with a longer full lowercase and a simple one. */
return ch == 0x0130 ? 0x0069 : ch;
}
return _PyUnicode_ExtendedCase[ctype->lower & 0xFFFF];
}
return ch + ctype->lower;
}

Expand Down
Loading