在Java中将国际字符串转换为\u代码

54

如何将国际化字符串(例如俄语)转换为 \u 数字 (unicode 数字)?
例如,将字符串 OK 转换为 \u041e\u041a?

12个回答

62

有一个JDK工具可以通过命令行执行,如下所示:

native2ascii -encoding utf8 src.txt output.txt

例子:

src.txt

بسم الله الرحمن الرحيم

output.txt

\u0628\u0633\u0645 \u0627\u0644\u0644\u0647 \u0627\u0644\u0631\u062d\u0645\u0646 \u0627\u0644\u0631\u062d\u064a\u0645

如果你想在Java应用程序中使用它,可以通过以下方式包装此命令行:

String pathSrc = "./tmp/src.txt";
String pathOut = "./tmp/output.txt";
String cmdLine = "native2ascii -encoding utf8 " + new File(pathSrc).getAbsolutePath() + " " + new File(pathOut).getAbsolutePath();
Runtime.getRuntime().exec(cmdLine);
System.out.println("THE END");

然后阅读新文件的内容。


4
你可以不启动一个子进程来完成它,参见http://stackoverflow.com/a/6017769/115493。 - mik01aj
这个gist将上面的命令行示例封装在一个Bash脚本中,使其更易于使用。 - dvlcube
1
这个工具在Java 9中被移除了:https://dev59.com/1Jrga4cB1Zd3GeqPpZoG - Nicolas Raoul
那么既然native2ascii已经消失了,现在有什么替代方案呢? - Martynas Jusevičius

24
你可以使用来自org.apache.commons.lang.StringEscapeUtilsescapeJavaStyleString

9
在3.x版本中,这个方法已经更名为escapeJava。请点击escapeJava以获取更多信息。 - Brad Mace
and doesn't escape to \uXXXX - Marc
最好不要使用它 ;) 查看答案:https://dev59.com/63A65IYBdhLWcg3w-jum#4298836 - mik01aj
6
该方法还可以转义其他特殊符号,例如引号(")。这可能是一种不希望出现的行为。 - hoodieman

16

我也遇到了这个问题。我有一些葡萄牙文本带有一些特殊字符,但这些字符已经以unicode格式存在(例如:\u00e3)。

所以我想把 S\u00e3o 转换成 São

我使用了apache commons的StringEscapeUtils,就像@sorin-sbarnea所说的那样。可以在这里下载。

使用unescapeJava方法,如下:

String text = "S\u00e3o"
text = StringEscapeUtils.unescapeJava(text);
System.out.println("text " + text);

(还有一个方法叫做escapeJava,但是它会把unicode字符放入字符串中。)

如果有人知道一个纯Java的解决方案,请告诉我们。


你做反了,那不是 OP 所要求的。 - mik01aj

16

这是 ArtB的回答 的改进版本:

    StringBuilder b = new StringBuilder();

    for (char c : input.toCharArray()) {
        if (c >= 128)
            b.append("\\u").append(String.format("%04X", (int) c));
        else
            b.append(c);
    }

    return b.toString();

此版本转义所有非ASCII字符,并正确处理低Unicode码点,如Ä


1
它是否适用于多字节字符,例如当4-6-8个字节(2、3、4个Java char值)连续表示一个符号时? - radistao
它不会,因为它正在使用单个“char”进行迭代。 - mik01aj

12

回答分为三部分:

  1. 获取每个字符的Unicode
  2. 判断是否在Cyrillic页面中
  3. 将其转换为十六进制。

要获取每个字符,可以使用 charAt()toCharArray() 方法迭代字符串。

for( char c : s.toCharArray() )

该字符的值是Unicode值。

Cyrillic Unicode 字符是以下范围内的任何字符:

Cyrillic:            U+0400–U+04FF ( 1024 -  1279)
Cyrillic Supplement: U+0500–U+052F ( 1280 -  1327)
Cyrillic Extended-A: U+2DE0–U+2DFF (11744 - 11775)
Cyrillic Extended-B: U+A640–U+A69F (42560 - 42655)

如果在这个范围内,它就是西里尔文。只需执行一个if检查。如果在该范围内,请使用 Integer.toHexString() 并在前面添加 "\\u"。组合起来应该看起来像这样:

final int[][] ranges = new int[][]{ 
        {  1024,  1279 }, 
        {  1280,  1327 }, 
        { 11744, 11775 }, 
        { 42560, 42655 },
    };
StringBuilder b = new StringBuilder();

for( char c : s.toCharArray() ){
    int[] insideRange = null;
    for( int[] range : ranges ){
        if( range[0] <= c && c <= range[1] ){
            insideRange = range;
            break;
        }
    }

    if( insideRange != null ){
        b.append( "\\u" ).append( Integer.toHexString(c) );
    }else{
        b.append( c );
    }
}

return b.toString();

编辑: 可能应该将检查条件更改为 c < 128 并颠倒 ifelse 的主体;你们可能需要转义所有非ASCII字符。在阅读您的问题时,我可能太过字面了。


这是我上下文中的正确答案。然而,我认为“getCharArray()”应该改为“toCharArray”。 - Jen S.
@JenS。非常感谢,实际上该方法是toCharArray() - Sled
这并不适用于所有Unicode字符!例如对于德语Ä,它返回\uC4而不是\u00c4 - mik01aj
@m01 我相信问题的原始形式是关于俄语字符的。 - Sled
俄语只是一个例子。您的例子虽然可以,但 if 中的范围检查可以防止此情况发生。还请参考我提供的通用方法解答。 - mik01aj
“char”的值是Unicode值。更具体地说,它是UTF-16代码单元值,每个Unicode代码点有一个或两个UTF-16代码单元。UTF-16代码单元是构建Java源代码字符转义(无论是否在字面字符串中使用)所需的内容。 - Tom Blodget

7

Java自带了一个命令行工具,叫做native2ascii。它可以将Unicode文件转换为ASCII转义文件。我发现这是生成本地化.properties文件的必要步骤。


6
如果您需要编写 .properties 文件,只需将字符串添加到 Properties 对象中,然后将其保存到文件中即可。它会自动进行转换。

你需要确保将文件保存为UTF-8格式(也许UTF-16或UCS-2/4也可以),否则会出现问题。 - Sled
7
@ArtB: 不,Properties始终将输入文件解释为ISO-8859-1(第一个Unicode页面),并且也保存到该编码中。这就是为什么它需要\uXXXX转义并在保存时创建它们的原因。虽然自Java版本1.6起,Properties允许从Reader对象中读取输入,因此您可以创建自己专有的基于UTF-8的属性文件格式。 - x4u
是的,对于那些使用大量8859-1字符集外字符的语言而言,\uXXXX 编码产生的文件相对较大,因为其空间利用率不如UTF-8或UTF-16。它还使得在任何不知道这种特殊编码的编辑器中都无法编辑这些文件。但至少它允许保存和加载所有Unicode文本,只要Java VM通常支持这种程度。 - x4u
4
这就是为什么我写了“只要Java虚拟机一般支持的范围内”。实际上,除了BMP字符外,Java也支持超出BMP字符,因为Java将这些字符视为代理对,并且它们也可以被编码为\u对。但在Java中,代理的支持程度差异很大,有些几乎不存在,有些在XML解析器或某些Swing组件中略微支持。此外,java.lang中的许多基本字符串操作例程现在似乎已经意识到代理(除了我所知道的regexp之外),但如果需要,仍然可以在它们的中间截断字符串。 - x4u
这似乎是一个非常绕弯的解决方案。从问题中,我假设我们正在寻找某种方法调用String->String。 - Michael Haefele
显示剩余2条评论

5

Apache Commons的StringEscapeUtils.escapeEcmaScript(String)方法可以将字符串中的Unicode字符使用\u符号进行转义。

"Art of Beer  " -> "Art of Beer \u1F3A8 \u1F37A"

4

有一个开源的Java库MgntUtils,其中有一个实用程序可以将字符串转换为Unicode序列,反之亦然:

result = "Hello World";
result = StringUnicodeEncoderDecoder.encodeStringToUnicodeSequence(result);
System.out.println(result);
result = StringUnicodeEncoderDecoder.decodeUnicodeSequenceToString(result);
System.out.println(result);

这段代码的输出是:
\u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064
Hello World

该库可在Maven CentralGithub找到,是一个maven构件包含源代码和javadoc文档。
以下是类StringUnicodeEncoderDecoder的javadoc文档。

这个非常有用的库。它解决了我从西里尔文转换为Unicode的问题。谢谢Michael。 - Zafer
@Zafer,我很高兴这个库对你有用。能否请你帮个小忙?你可以去我的库的文章留下评论吗?这是两个链接:https://www.linkedin.com/pulse/open-source-java-library-some-useful-utilities-michael-gantman/,https://community.oracle.com/blogs/michaelgantman/2016/01/26/open-source-java-library-with-stacktrace-filtering-silent-string-parsing-and-version-comparison - Michael Gantman

3
以下是一些基本方法(灵感来自于native2ascii工具):

仅需几个基本步骤:

/**
 * Encode a String like äöü to \u00e4\u00f6\u00fc
 * 
 * @param text
 * @return
 */
public String native2ascii(String text) {
    if (text == null)
        return text;
    StringBuilder sb = new StringBuilder();
    for (char ch : text.toCharArray()) {
        sb.append(native2ascii(ch));
    }
    return sb.toString();
}

/**
 * Encode a Character like ä to \u00e4
 * 
 * @param ch
 * @return
 */
public String native2ascii(char ch) {
    if (ch > '\u007f') {
        StringBuilder sb = new StringBuilder();
        // write \udddd
        sb.append("\\u");
        StringBuffer hex = new StringBuffer(Integer.toHexString(ch));
        hex.reverse();
        int length = 4 - hex.length();
        for (int j = 0; j < length; j++) {
            hex.append('0');
        }
        for (int j = 0; j < 4; j++) {
            sb.append(hex.charAt(3 - j));
        }
        return sb.toString();
    } else {
        return Character.toString(ch);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接