Skip to content

Commit 02d54b9

Browse files
committed
Implement str.swapcase
Fixes #154
1 parent bc47380 commit 02d54b9

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_unicode.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_formatting_with_enum
4545
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_free_after_iterating
4646
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_hash
47+
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_inplace_rewrites
4748
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_invalid_cb_for_2bytes_seq
4849
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_invalid_cb_for_4bytes_seq
4950
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_invalid_start_byte
@@ -57,6 +58,7 @@
5758
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_isnumeric
5859
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_isprintable
5960
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_isspace
61+
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_issue18183
6062
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_issue28598_strsubclass_rhs
6163
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_issue8271
6264
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_istitle
@@ -93,6 +95,7 @@
9395
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_subclass_add
9496
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_subscript
9597
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_surrogates
98+
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_swapcase
9699
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_title
97100
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_unexpected_end_of_data
98101
*graalpython.lib-python.3.test.test_unicode.UnicodeTest.test_unicode_repr

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
@@ -2278,4 +2278,68 @@ static String doGeneric(Object self,
22782278
return doString(castSelfNode.cast(self, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, "casefold", self));
22792279
}
22802280
}
2281+
2282+
@Builtin(name = "swapcase", minNumOfPositionalArgs = 1)
2283+
@GenerateNodeFactory
2284+
public abstract static class SwapCaseNode extends PythonUnaryBuiltinNode {
2285+
2286+
private static final int CAPITAL_SIGMA = 0x3A3;
2287+
2288+
@Specialization
2289+
@TruffleBoundary
2290+
static String doString(String self) {
2291+
StringBuilder sb = new StringBuilder(self.length());
2292+
for (int i = 0; i < self.length();) {
2293+
int codePoint = self.codePointAt(i);
2294+
int charCount = Character.charCount(codePoint);
2295+
String substr = self.substring(i, i + charCount);
2296+
if (UCharacter.isUUppercase(codePoint)) {
2297+
// Special case for capital sigma, needed because ICU4J doesn't have the context
2298+
// of the whole string
2299+
if (codePoint == CAPITAL_SIGMA) {
2300+
handleCapitalSigma(self, sb, i, codePoint);
2301+
} else {
2302+
sb.append(UCharacter.toLowerCase(Locale.ROOT, substr));
2303+
}
2304+
} else if (UCharacter.isULowercase(codePoint)) {
2305+
sb.append(UCharacter.toUpperCase(Locale.ROOT, substr));
2306+
} else {
2307+
sb.append(substr);
2308+
}
2309+
i += charCount;
2310+
}
2311+
return sb.toString();
2312+
}
2313+
2314+
// Adapted from unicodeobject.c:handle_capital_sigma
2315+
private static void handleCapitalSigma(String self, StringBuilder sb, int i, int codePoint) {
2316+
int j;
2317+
for (j = i - 1; j >= 0; j--) {
2318+
if (!Character.isHighSurrogate(self.charAt(j))) {
2319+
int ch = self.codePointAt(j);
2320+
if (!UCharacter.hasBinaryProperty(ch, UProperty.CASE_IGNORABLE)) {
2321+
break;
2322+
}
2323+
}
2324+
}
2325+
boolean finalSigma = j >= 0 && UCharacter.hasBinaryProperty(codePoint, UProperty.CASED);
2326+
if (finalSigma) {
2327+
for (j = i + 1; j < self.length();) {
2328+
int ch = self.codePointAt(j);
2329+
if (!UCharacter.hasBinaryProperty(ch, UProperty.CASE_IGNORABLE)) {
2330+
break;
2331+
}
2332+
j += Character.charCount(ch);
2333+
}
2334+
finalSigma = j == self.length() || !UCharacter.hasBinaryProperty(codePoint, UProperty.CASED);
2335+
}
2336+
sb.appendCodePoint(finalSigma ? 0x3C2 : 0x3C3);
2337+
}
2338+
2339+
@Specialization(replaces = "doString")
2340+
static String doGeneric(Object self,
2341+
@Cached CastToJavaStringCheckedNode castSelfNode) {
2342+
return doString(castSelfNode.cast(self, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, "swapcase", self));
2343+
}
2344+
}
22812345
}

0 commit comments

Comments
 (0)