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 085c2dd9e Pad BMP code points to four hex digits in
UnicodeEscaper.toUtf16Escape (#1858)
085c2dd9e is described below
commit 085c2dd9e8ad82750e6d0cca0492d6bf2f0e16db
Author: alhuda <[email protected]>
AuthorDate: Tue Nov 3 19:01:36 2026 +0530
Pad BMP code points to four hex digits in UnicodeEscaper.toUtf16Escape
(#1858)
The BMP branch of the protected toUtf16Escape hook returned "\\u" +
Integer.toHexString, so code points below U+1000 produced short escapes
such as \u41 that no \u reader decodes, while translate() pads the same
code point through HEX_DIGITS. JavaUnicodeEscaper overrode the hook with
the surrogate-pair form only and threw ArrayIndexOutOfBoundsException
for every BMP code point.
Left-pad the BMP hex to four digits and drop the JavaUnicodeEscaper
override, which is redundant since the base method emits the
surrogate-pair form itself. translate() output is unchanged.
---
.../lang3/text/translate/JavaUnicodeEscaper.java | 13 -------
.../lang3/text/translate/UnicodeEscaper.java | 4 ++-
...scaperTest.java => JavaUnicodeEscaperTest.java} | 42 +++++++---------------
.../lang3/text/translate/UnicodeEscaperTest.java | 13 +++++++
4 files changed, 29 insertions(+), 43 deletions(-)
diff --git
a/src/main/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaper.java
b/src/main/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaper.java
index 4ddca9ad4..0dbe5d7ed 100644
---
a/src/main/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaper.java
+++
b/src/main/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaper.java
@@ -91,17 +91,4 @@ public JavaUnicodeEscaper(final int below, final int above,
final boolean betwee
super(below, above, between);
}
- /**
- * Converts the given code point to a hexadecimal string of the form
{@code "\\uXXXX\\uXXXX"}
- *
- * @param codePoint
- * a Unicode code point.
- * @return The hexadecimal string for the given code point.
- */
- @Override
- protected String toUtf16Escape(final int codePoint) {
- final char[] surrogatePair = Character.toChars(codePoint);
- return "\\u" + hex(surrogatePair[0]) + "\\u" + hex(surrogatePair[1]);
- }
-
}
diff --git
a/src/main/java/org/apache/commons/lang3/text/translate/UnicodeEscaper.java
b/src/main/java/org/apache/commons/lang3/text/translate/UnicodeEscaper.java
index 64bff2819..6725fe50c 100644
--- a/src/main/java/org/apache/commons/lang3/text/translate/UnicodeEscaper.java
+++ b/src/main/java/org/apache/commons/lang3/text/translate/UnicodeEscaper.java
@@ -19,6 +19,8 @@
import java.io.IOException;
import java.io.Writer;
+import org.apache.commons.lang3.StringUtils;
+
/**
* Translates code points to their Unicode escaped value.
*
@@ -112,7 +114,7 @@ protected UnicodeEscaper(final int below, final int above,
final boolean between
*/
protected String toUtf16Escape(final int codePoint) {
if (Character.isBmpCodePoint(codePoint)) {
- return "\\u" + hex(codePoint);
+ return "\\u" + StringUtils.leftPad(hex(codePoint), 4, '0');
}
final char[] surrogatePair = Character.toChars(codePoint);
return "\\u" + hex(surrogatePair[0]) + "\\u" + hex(surrogatePair[1]);
diff --git
a/src/test/java/org/apache/commons/lang3/text/translate/UnicodeEscaperTest.java
b/src/test/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaperTest.java
similarity index 51%
copy from
src/test/java/org/apache/commons/lang3/text/translate/UnicodeEscaperTest.java
copy to
src/test/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaperTest.java
index 6d2094943..e4842cc14 100644
---
a/src/test/java/org/apache/commons/lang3/text/translate/UnicodeEscaperTest.java
+++
b/src/test/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaperTest.java
@@ -23,42 +23,26 @@
import org.junit.jupiter.api.Test;
/**
- * Tests for {@link org.apache.commons.lang3.text.translate.UnicodeEscaper}.
+ * Tests for {@link
org.apache.commons.lang3.text.translate.JavaUnicodeEscaper}.
*/
@Deprecated
-class UnicodeEscaperTest extends AbstractLangTest {
-
- @Test
- void testAbove() {
- final UnicodeEscaper ue = UnicodeEscaper.above('F');
- final String input = "ADFGZ";
- final String result = ue.translate(input);
- assertEquals("ADF\\u0047\\u005A", result, "Failed to escape Unicode
characters via the above method");
- }
-
- @Test
- void testBelow() {
- final UnicodeEscaper ue = UnicodeEscaper.below('F');
- final String input = "ADFGZ";
- final String result = ue.translate(input);
- assertEquals("\\u0041\\u0044FGZ", result, "Failed to escape Unicode
characters via the below method");
- }
-
- @Test
- void testBetween() {
- final UnicodeEscaper ue = UnicodeEscaper.between('F', 'L');
- final String input = "ADFGZ";
- final String result = ue.translate(input);
- assertEquals("AD\\u0046\\u0047Z", result, "Failed to escape Unicode
characters via the between method");
- }
+class JavaUnicodeEscaperTest extends AbstractLangTest {
@Test
void testSupplementary() {
- final UnicodeEscaper ue = UnicodeEscaper.above(0x7f);
+ final JavaUnicodeEscaper jue = JavaUnicodeEscaper.above(0x7f);
// U+10437 (DESERET SMALL LETTER YEE) encodes to surrogate pair U+D801
U+DC37.
final String input = new String(Character.toChars(0x10437));
- final String result = ue.translate(input);
+ final String result = jue.translate(input);
assertEquals("\\uD801\\uDC37", result, "Supplementary code point must
escape to a surrogate pair");
- assertEquals(input, new UnicodeUnescaper().translate(result), "Escaped
supplementary code point must round-trip");
+ assertEquals("\\uD801\\uDC37", jue.toUtf16Escape(0x10437),
"toUtf16Escape must emit the surrogate pair form");
+ }
+
+ @Test
+ void testToUtf16EscapeBmp() {
+ final JavaUnicodeEscaper jue = new JavaUnicodeEscaper(0,
Integer.MAX_VALUE, true);
+ assertEquals("\\u0041", jue.toUtf16Escape('A'), "BMP code point must
escape to a single \\uXXXX");
+ assertEquals("\\uFFFF", jue.toUtf16Escape(0xFFFF), "BMP code point
must escape to a single \\uXXXX");
+ assertEquals(jue.translate("A"), jue.toUtf16Escape('A'),
"toUtf16Escape must match the translate output");
}
}
diff --git
a/src/test/java/org/apache/commons/lang3/text/translate/UnicodeEscaperTest.java
b/src/test/java/org/apache/commons/lang3/text/translate/UnicodeEscaperTest.java
index 6d2094943..523addb2d 100644
---
a/src/test/java/org/apache/commons/lang3/text/translate/UnicodeEscaperTest.java
+++
b/src/test/java/org/apache/commons/lang3/text/translate/UnicodeEscaperTest.java
@@ -52,6 +52,19 @@ void testBetween() {
assertEquals("AD\\u0046\\u0047Z", result, "Failed to escape Unicode
characters via the between method");
}
+ @Test
+ void testToUtf16EscapeBmp() {
+ final UnicodeEscaper ue = new UnicodeEscaper();
+ // A BMP code point below U+1000 needs zero padding to keep the four
digit \\uXXXX form.
+ assertEquals("\\u0000", ue.toUtf16Escape(0), "Code point 0 must escape
to four hex digits");
+ assertEquals("\\u000A", ue.toUtf16Escape('\n'), "Code point 0xA must
escape to four hex digits");
+ assertEquals("\\u0041", ue.toUtf16Escape('A'), "Code point 0x41 must
escape to four hex digits");
+ assertEquals("\\u0FFF", ue.toUtf16Escape(0xFFF), "Code point 0xFFF
must escape to four hex digits");
+ assertEquals("\\uFFFF", ue.toUtf16Escape(0xFFFF), "Code point 0xFFFF
must escape to four hex digits");
+ assertEquals(ue.translate("A"), ue.toUtf16Escape('A'), "toUtf16Escape
must match the translate output");
+ assertEquals("A", new
UnicodeUnescaper().translate(ue.toUtf16Escape('A')), "Escaped BMP code point
must round-trip");
+ }
+
@Test
void testSupplementary() {
final UnicodeEscaper ue = UnicodeEscaper.above(0x7f);