Skip to content

Commit 99cfb32

Browse files
committed
[GR-11899] str.title function is not implemented.
PullRequest: graalpython/212
2 parents 7b8a4cd + 2558e04 commit 99cfb32

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_string.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,32 @@ def __index__(self):
716716

717717
self.checkequal('0123', '123', 'zfill', MyIndexable(4))
718718

719+
def test_title(self):
720+
self.checkequal(' Hello ', ' hello ', 'title')
721+
self.checkequal('Hello ', 'hello ', 'title')
722+
self.checkequal('Hello ', 'Hello ', 'title')
723+
self.checkequal('Format This As Title String', "fOrMaT thIs aS titLe String", 'title')
724+
self.checkequal('Format,This-As*Title;String', "fOrMaT,thIs-aS*titLe;String", 'title', )
725+
self.checkequal('Getint', "getInt", 'title')
726+
self.checkraises(TypeError, 'hello', 'title', 42)
727+
728+
def test_title_uni(self):
729+
self.assertEqual('\U0001044F'.title(), '\U00010427')
730+
self.assertEqual('\U0001044F\U0001044F'.title(),
731+
'\U00010427\U0001044F')
732+
self.assertEqual('\U0001044F\U0001044F \U0001044F\U0001044F'.title(),
733+
'\U00010427\U0001044F \U00010427\U0001044F')
734+
self.assertEqual('\U00010427\U0001044F \U00010427\U0001044F'.title(),
735+
'\U00010427\U0001044F \U00010427\U0001044F')
736+
self.assertEqual('\U0001044F\U00010427 \U0001044F\U00010427'.title(),
737+
'\U00010427\U0001044F \U00010427\U0001044F')
738+
self.assertEqual('X\U00010427x\U0001044F X\U00010427x\U0001044F'.title(),
739+
'X\U0001044Fx\U0001044F X\U0001044Fx\U0001044F')
740+
self.assertEqual('fiNNISH'.title(), 'Finnish')
741+
self.assertEqual('bfiNNISH'.title(), 'Bfinnish')
742+
self.assertEqual('fifiNNfiISH'.title(), 'Fifinnfiish')
743+
self.assertEqual('A\u03a3A'.title(), 'A\u03c3a')
744+
719745
def test_same_id():
720746
empty_ids = set([id(str()) for i in range(100)])
721747
assert len(empty_ids) == 1

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,6 +1600,70 @@ public static ZFillNode create() {
16001600
}
16011601
}
16021602

1603+
@Builtin(name = "title", fixedNumOfPositionalArgs = 1)
1604+
@GenerateNodeFactory
1605+
@TypeSystemReference(PythonArithmeticTypes.class)
1606+
abstract static class TitleNode extends PythonUnaryBuiltinNode {
1607+
1608+
@Specialization
1609+
@TruffleBoundary
1610+
public String doTitle(String self) {
1611+
boolean shouldBeLowerCase = false;
1612+
boolean translated;
1613+
StringBuilder converted = new StringBuilder();
1614+
for (int offset = 0; offset < self.length();) {
1615+
int ch = self.codePointAt(offset);
1616+
translated = false;
1617+
if (Character.isAlphabetic(ch)) {
1618+
if (shouldBeLowerCase) {
1619+
// Should be lower case
1620+
if (Character.isUpperCase(ch)) {
1621+
translated = true;
1622+
if (ch < 256) {
1623+
converted.append((char) Character.toLowerCase(ch));
1624+
} else {
1625+
String origPart = new String(Character.toChars(ch));
1626+
String changedPart = origPart.toLowerCase();
1627+
converted.append(changedPart);
1628+
}
1629+
}
1630+
} else {
1631+
// Should be upper case
1632+
if (Character.isLowerCase(ch)) {
1633+
translated = true;
1634+
if (ch < 256) {
1635+
converted.append((char) Character.toUpperCase(ch));
1636+
} else {
1637+
String origPart = new String(Character.toChars(ch));
1638+
String changedPart = origPart.toUpperCase();
1639+
if (origPart.length() < changedPart.length()) {
1640+
// the original char was mapped to more chars ->
1641+
// we need to make upper case just the first one
1642+
changedPart = doTitle(changedPart);
1643+
}
1644+
converted.append(changedPart);
1645+
}
1646+
}
1647+
}
1648+
// And this was a letter
1649+
shouldBeLowerCase = true;
1650+
} else {
1651+
// This was not a letter
1652+
shouldBeLowerCase = false;
1653+
}
1654+
if (!translated) {
1655+
if (ch < 256) {
1656+
converted.append((char) ch);
1657+
} else {
1658+
converted.append(Character.toChars(ch));
1659+
}
1660+
}
1661+
offset += Character.charCount(ch);
1662+
}
1663+
return converted.toString();
1664+
}
1665+
}
1666+
16031667
@Builtin(name = __GETITEM__, fixedNumOfPositionalArgs = 2)
16041668
@GenerateNodeFactory
16051669
@TypeSystemReference(PythonArithmeticTypes.class)

0 commit comments

Comments
 (0)