我该如何将代表码点的字符串转换为相应的字符?
例如,我想要一个函数,输入 U+00E4
并返回 ä
。
虽然在字符类中有一个接受整数的函数 toChars(int codePoint)
,但没有接受这种类型字符串的函数。
是否有内置函数可以使用,还是我需要对字符串进行某些转换以获取整数,然后再调用该函数?
码点以十六进制数字为前缀的 U+
写出。
因此,你可以这样做。
int codepoint=Integer.parseInt(yourString.substring(2),16);
char[] ch=Character.toChars(codepoint);
这个问题要求一个函数用于将代表Unicode码点的字符串值转换为相应的字符 (即"+Unnnn"
,而不是Java格式的"\unnnn"
或"0xnnnn"
)。然而,Java的更新版本增加了一些功能,可以简化包含多个Unicode格式码点的字符串的处理:
Character
类添加了一个方法public static String toString(int codePoint)
。它返回一个String
而不是char[]
,所以Character.toString(0x00E4)
返回"ä"
。这些增强功能允许使用不同的方法来解决OP提出的问题。这种方法可以在一个语句中将Unicode格式的一组码点转换为可读的String
:
void processUnicode() {
// Create a test string containing "Hello World " with code points in Unicode format.
// Include an invalid code point (+U0wxyz), and a code point outside the Unicode range (+U70FFFF).
String data = "+U0048+U0065+U006c+U006c+U0wxyz+U006f+U0020+U0057+U70FFFF+U006f+U0072+U006c+U0000064+U20+U1f601";
String text = Arrays.stream(data.split("\\+U"))
.filter(s -> ! s.isEmpty()) // First element returned by split() is a zero length string.
.map(s -> {
try {
return Integer.parseInt(s, 16);
} catch (NumberFormatException e) {
System.out.println("Ignoring element [" + s + "]: NumberFormatException from parseInt(\"" + s + "\"}");
}
return null; // If the code point is not represented as a valid hex String.
})
.filter(v -> v != null) // Ignore syntactically invalid code points.
.filter(i -> Character.isValidCodePoint(i)) // Ignore code points outside of Unicode range.
.map(i -> Character.toString(i)) // Obtain the string value directly from the code point. (Requires JDK >= 11 )
.collect(Collectors.joining());
System.out.println(text); // Prints "Hello World "
}
这是输出结果:
run:
Ignoring element [0wxyz]: NumberFormatException from parseInt("0wxyz"}
Hello World
BUILD SUCCESSFUL (total time: 0 seconds)
注:
Stream
处理中分散了这个需求。当然,同样的代码仍然可以用于处理Unicode格式中的单个代码点。Stream
执行进一步的验证和处理,例如大小写转换、删除表情符号等。new String(Character.toChars(i))
来代替Character.toString(i)
。 - undefinedCharacter.toChars(int codePoint)
。 - undefined在 String
上调用 这个构造函数。
"\u00E4"
new String(new int[] { 0x00E4 }, 0, 1);
U+00E4
字符串形式存在的。 - Anirudha"\u00e4"
是否被认为是等价的(也就是在 Java 源代码中)。我给你点赞。 - Joop Eggen从 Kotlin 转换:
public String codepointToString(int cp) {
StringBuilder sb = new StringBuilder();
if (Character.isBmpCodePoint(cp)) {
sb.append((char) cp);
} else if (Character.isValidCodePoint(cp)) {
sb.append(Character.highSurrogate(cp));
sb.append(Character.lowSurrogate(cp));
} else {
sb.append('?');
}
return sb.toString();
}
/u
字符串而不是实际值。 - nullsector76这个例子没有使用char[]。
// this code is Kotlin, but you can write same thing in Java
val sb = StringBuilder()
val cp :Int // codepoint
when {
Character.isBmpCodePoint(cp) -> sb.append(cp.toChar())
Character.isValidCodePoint(cp) -> {
sb.append(Character.highSurrogate(cp))
sb.append(Character.lowSurrogate(cp))
}
else -> sb.append('?')
}
stringBuilder.appendCodePoint(cp)
,而不需要这样做。 - Callum Rogersjshell> Character.toString(Integer.parseInt("U+00E4".substring(2), 16))
$1 ==> "ä"
嗯,第二部分是不可能的,因为代码点可能有4个字节,而char数据类型只能容纳2个字节。
因此,如果在Java中永远不使用char数据类型,使用int或String代替可能是更一般化的方法。
用于保存代码点的数据类型是什么? 单个代码点可以保存在int数据类型中。 Unicode字符串在技术上是int数组,而不是char数组。
String smiley = new String(new int[] { 0x1F600 }, 0, 1); //int[] array of int codepoints can be converted to string
System.out.println(" print smiley = "+smiley );
输出 打印笑脸 =
如果您正在使用IntelliJ idea,您可以复制输出的笑脸并粘贴到双引号字符串中。 您将得到这个"\uD83D\uDE00"
如果您打印此字符串,您将再次获得一个笑脸
System.out.println("\uD83D\uDE00");
输出
为什么我们不能在字符串中使用单个"\u"来表示笑脸? 因为当设计\u转义时,所有Unicode字符都可以用2个字节或4个十六进制数字表示。因此,在Java字符串文字中,\u后始终有4个十六进制数字。要表示更大的Unicode值,您需要更大的十六进制数,但这将破坏现有的Java字符串。因此,Java使用与UTF-16相同的方法。
以下两者是等效的。
String smiley = new String(new int[] { 0x1F600 }, 0, 1); //using single code point number
String smiley = "\uD83D\uDE00";//split code point in 2 parts of 2 bytes each (utf-16)
请参考此处的Java文档。
https://docs.oracle.com/javase/7/docs/api/java/lang/Character.html#unicode
Unicode字符表示s='\u0645\u0635\u0631\u064a'
print(s)
int codepoint = ...;
char c = (char)codepoint;
char
类型已经过时了许多年(几十年?),无法表示Unicode定义的一半字符。 - Basil Bourque
new StringBuilder().appendCodePoint(codepoint).toString().charAt(0)
的方法,但是请注意,超过 64k 的代码点会产生 两个 字符,高代理项和低代理项。您可能更喜欢去掉.charAt(0)
直接将结果作为String
获取。 - David Conrad