This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new c74771113 keep stripStart and stripEnd off surrogate pair boundaries
(#1773)
c74771113 is described below
commit c747711133c3e13d8d2bdab27a2eb7b11f1c6d7f
Author: alhuda <[email protected]>
AuthorDate: Fri Aug 14 19:56:52 2026 +0530
keep stripStart and stripEnd off surrogate pair boundaries (#1773)
---
.../java/org/apache/commons/lang3/StringUtils.java | 16 ++++++++++++----
.../org/apache/commons/lang3/StringUtilsStripTest.java | 18 ++++++++++++++++++
2 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java
b/src/main/java/org/apache/commons/lang3/StringUtils.java
index aefc9aa4c..647e351a9 100644
--- a/src/main/java/org/apache/commons/lang3/StringUtils.java
+++ b/src/main/java/org/apache/commons/lang3/StringUtils.java
@@ -8091,8 +8091,12 @@ public static String stripEnd(final String str, final
String stripChars) {
} else if (stripChars.isEmpty()) {
return str;
} else {
- while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) !=
INDEX_NOT_FOUND) {
- end--;
+ while (end != 0) {
+ final int codePoint = str.codePointBefore(end);
+ if (stripChars.indexOf(codePoint) == INDEX_NOT_FOUND) {
+ break;
+ }
+ end -= Character.charCount(codePoint);
}
}
return str.substring(0, end);
@@ -8137,8 +8141,12 @@ public static String stripStart(final String str, final
String stripChars) {
} else if (stripChars.isEmpty()) {
return str;
} else {
- while (start != strLen && stripChars.indexOf(str.charAt(start)) !=
INDEX_NOT_FOUND) {
- start++;
+ while (start != strLen) {
+ final int codePoint = str.codePointAt(start);
+ if (stripChars.indexOf(codePoint) == INDEX_NOT_FOUND) {
+ break;
+ }
+ start += Character.charCount(codePoint);
}
}
return str.substring(start);
diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsStripTest.java
b/src/test/java/org/apache/commons/lang3/StringUtilsStripTest.java
index dddca79b6..9c59239a7 100644
--- a/src/test/java/org/apache/commons/lang3/StringUtilsStripTest.java
+++ b/src/test/java/org/apache/commons/lang3/StringUtilsStripTest.java
@@ -241,6 +241,24 @@ void testStripStringString() {
assertEquals(StringUtilsTest.WHITESPACE,
StringUtils.strip(StringUtilsTest.WHITESPACE, ""));
}
+ @Test
+ void testStripSupplementaryCodePoints() {
+ // U+1D51E and U+1D51F share the high surrogate \uD835; U+1D11E shares
the low surrogate \uDD1E with U+1D51E.
+ final String mathA = "\uD835\uDD1E"; // U+1D51E
+ final String mathB = "\uD835\uDD1F"; // U+1D51F
+ final String clef = "\uD834\uDD1E"; // U+1D11E
+
+ // A supplementary strip character must not match a code point that
only shares one surrogate half.
+ assertEquals(mathA + "abc", StringUtils.stripStart(mathA + "abc",
mathB));
+ assertEquals("abc" + clef, StringUtils.stripEnd("abc" + clef, mathA));
+ assertEquals(mathA + "abc" + mathA, StringUtils.strip(mathA + "abc" +
mathA, mathB));
+
+ // Genuine membership still strips the whole supplementary code point.
+ assertEquals("abc", StringUtils.stripStart(mathA + mathA + "abc",
mathA));
+ assertEquals("abc", StringUtils.stripEnd("abc" + mathA + mathA,
mathA));
+ assertEquals("abc", StringUtils.strip(mathA + "abc" + mathA, mathA));
+ }
+
@Test
void testStripToEmptyString() {
assertEquals("", StringUtils.stripToEmpty(null));