我在 Java 中的字符串变量中有以下值,该变量具有如下编码的 UTF-8 字符
Dodd\u2013Frank
而不是
Dodd–Frank
(假设我无法控制如何将该值分配给该字符串变量)
现在如何正确转换(编码)它并将其存储回
String
变量中?
我找到了以下代码
Charset.forName("UTF-8").encode(str);
但这会返回一个
ByteBuffer
,但我想要一个 String
。
编辑:
更多附加信息。
当我使用
System.out.println(str);
我得到
Dodd\u2013Frank
我不确定正确的术语是什么(UTF-8 或 unicode)。请原谅我。
java.util.Properties
java.util.Properties
支持带有 \uXXXX
转义序列的字符串并执行以下操作:
Properties p = new Properties();
p.load(new StringReader("key = " + yourInputString));
System.out.println("Escaped value: " + p.getProperty("key"));
不优雅,但实用。
为了处理可能的
IOExeception
,您可能需要 try-catch。
Properties p = new Properties();
try {
p.load(new StringReader("key = " + input));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Escaped value: " + p.getProperty("key"));
尝试
str = org.apache.commons.text.StringEscapeUtils.unescapeJava(str);
因为 org.apache.commons.lang3.StringEscapeUtils 已被弃用。
假设您有一个 Unicode 值,例如 00B0(度数符号,或上标“o”,如西班牙语“primero”的缩写)
这是一个可以完成您想要的功能的函数:
public static String unicodeToString( char charValue )
{
Character ch = new Character( charValue );
return ch.toString();
}
我使用
StringEscapeUtils.unescapeXml
转义从提供 XML 结果的 API 加载的字符串。
UnicodeUnescaper
来自 org.apache.commons:commons-text
也可以接受。
new UnicodeUnescaper().translate("Dodd\u2013Frank")
如果您无法向项目添加依赖项,或者您根本不想这样做,这里有一个使用正则表达式的相对简单的实现。
import java.util.regex.Pattern;
public final class UnicodeUnescape {
private static final Pattern PATTERN = Pattern.compile("\\\\u(\\p{XDigit}{4})");
public static String unescape(String input) {
return PATTERN
.matcher(input)
.replaceAll(
match -> {
char c = (char) Integer.parseInt(match.group(1), 16);
return Character.toString(c);
});
}
}
虽然这显然不是最有效的实现。此外,这将仅处理Unicode转义序列,与
StringEscapeUtils#escapeJava(String)
来自Apache Commons Text不同。
Matcher#replaceAll(Function<MatchResult, String>)
。
这是一个非常基本的、非详尽的单元测试。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import java.util.List;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class UnicodeUnescapeTests {
@ParameterizedTest(name = "\"{0}\" → \"{1}\"")
@MethodSource
void testUnescape(String input, String expected) {
var actual = UnicodeUnescape.unescape(input);
assertEquals(expected, actual);
}
static List<Arguments> testUnescape() {
return List.of(
// test input from question
arguments("Dodd\\u2013Frank", "Dodd–Frank"),
// test surrogate pair
arguments("Dodd Frank \\uD83C\\uDF09", "Dodd Frank 🌉"));
}
}
输出(来自 Gradle):
UnicodeUnescapeTests > ... > "Dodd\u2013Frank" → "Dodd–Frank" PASSED
UnicodeUnescapeTests > ... > "Dodd Frank \uD83C\uDF09" → "Dodd Frank 🌉" PASSED
您可以像这样将该字节缓冲区转换为字符串:
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.ByteBuffer
public static CharsetDecoder decoder = CharsetDecoder.newDecoder();
public static String byteBufferToString(ByteBuffer buffer)
{
String data = "";
try
{
// EDITOR'S NOTE -- There is no 'position' method for ByteBuffer.
// As such, this is pseudocode.
int old_position = buffer.position();
data = decoder.decode(buffer).toString();
// reset buffer's position to its original so it is not altered:
buffer.position(old_position);
}
catch (Exception e)
{
e.printStackTrace();
return "";
}
return data;
}
也许以下解决方案可以正确解码字符串,而无需任何额外的依赖项。
这在 scala repl 中有效,但在纯 Java 解决方案中应该同样有效。
import java.nio.charset.StandardCharsets
import java.nio.charset.Charset
> StandardCharsets.UTF_8.decode(Charset.forName("UTF-8").encode("Dodd\u2013Frank"))
res: java.nio.CharBuffer = Dodd–Frank