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));

Reply via email to