Unicodeエンコーディングの文字列を文字列に変換する方法


82

私はエスケープされた文字列持ちのUnicode文字を、\uXXXXと私は定期的にUnicodeの文字に変換します。例えば:

"\u0048\u0065\u006C\u006C\u006F World"

になるはずです

"Hello World"

最初の文字列を印刷すると、すでにが表示されていることを知っていますHello world。私の問題は、ファイルからファイル名を読み取り、それらを検索することです。ファイル内のファイル名はUnicodeエンコーディングでエスケープされており、ファイルを検索すると、名前に含まれるファイルが検索されるため、ファイルが見つかりません\uXXXX


確かですか?Unicodeエスケープとして文字が単に印刷されるとは思いませんか?
Hot Licks

5
\u0048 H-それらは同じものです。Javaの文字列はUnicodeです。
Hot Licks 2012年

問題は、JavaからUNIXへのAPIにあると思います。取得する文字列は、\ u3123 \ u3255_file_name.txtのようなものです。そして、Javaはそれを隠しません。
SharonBL 2012年

3
UTF-8Unicodeエンコーディングです。
Pavel Radzivilovsky 2012年

5
これはあなたの質問に対する答えではありませんが、多くの人が混乱しているように見えるUnicodeとUTF-8の違いを明確にしましょう。Unicodeは、特定のある1対1我々は(彼らを知っているように、文字間のマッピングab$£整数に、など)。たとえば、記号にAは番号65が付けられ、\n10です。これは、文字列や文字がディスクやテキストファイルでどのように表現されるかとは関係ありません。UTF-8は、これらの整数(つまりシンボル)をバイト(ビット文字列)として表す方法の仕様(つまりエンコード)であるため、ファイルなどから明確に読み書きできます。
DustByte 2016年

回答:


48

技術的に:

String myString = "\u0048\u0065\u006C\u006C\u006F World";

自動的にに変換される"Hello World"ので、あるファイルから文字列を読み込んでいると思います。それを「Hello」に変換するには、テキストを個別のUnicode桁に解析する必要があります(を取得して取得する\uXXXXだけですXXXX)。次にInteger.ParseInt(XXXX, 16)、16進値を取得し、それを大文字と小文字を区別してchar実際の文字を取得します。

編集:これを達成するためのいくつかのコード:

String str = myString.split(" ")[0];
str = str.replace("\\","");
String[] arr = str.split("u");
String text = "";
for(int i = 1; i < arr.length; i++){
    int hexVal = Integer.parseInt(arr[i], 16);
    text += (char)hexVal;
}
// Text will now have Hello

それが解決策かもしれないようです。Javaでそれを行う方法を知っていますか?String.replaceAllまたはそのようなものでそれを行うことができますか?
SharonBL 2012年

@SharonBLいくつかのコードで更新しましたが、少なくともどこから始めればよいかがわかるはずです。
NominSim 2012年

2
助けてくれてありがとう!そのための別の解決策も見つけました:String s = StringEscapeUtils.unescapeJava( "\\ u20ac \\ n"); それは仕事をします!
SharonBL 2012年

2
標準Javaライブラリによって提供されるメソッドを再発明しようとします。純粋な実装を確認するだけですstackoverflow.com/a/39265921/1511077–
Evgeny Lebedev

1
車輪の再発明」の答えが非常に多くの票を獲得したとき、私はいつも驚いています。
ペドロロビト2018

92

Apacheのコモンズラング StringEscapeUtils.unescapeJava()はそれを正しくデコードすることができます。

import org.apache.commons.lang.StringEscapeUtils;

@Test
public void testUnescapeJava() {
    String sJava="\\u0048\\u0065\\u006C\\u006C\\u006F";
    System.out.println("StringEscapeUtils.unescapeJava(sJava):\n" + StringEscapeUtils.unescapeJava(sJava));
}


 output:
 StringEscapeUtils.unescapeJava(sJava):
 Hello

文字列sJava = "\ u0048 \\ u0065 \ u006C \ u006C \ u006F"; ----->簡単な変更をお願いします。
Shreyansh Shah

29

Apache Commons LangStringEscapeUtilsから使用できます。つまり、次のようになります。

String Title = StringEscapeUtils.unescapeJava("\\u0048\\u0065\\u006C\\u006C\\u006F");


5
build.gradleに依存関係を追加した後:上記の「commons-lang:commons-lang:2.6」を正常にコンパイルします。
ジョセフメクワン2015

8

この単純な方法はほとんどの場合に機能しますが、文字列「\ u0048」にデコードする必要がある「u005Cu005C」のようなものにつまずきますが、最初のパスが作業文字列として「\ u0048」を生成するため、実際には「H」をデコードします。その後、whileループによって再度処理されます。

static final String decode(final String in)
{
    String working = in;
    int index;
    index = working.indexOf("\\u");
    while(index > -1)
    {
        int length = working.length();
        if(index > (length-6))break;
        int numStart = index + 2;
        int numFinish = numStart + 4;
        String substring = working.substring(numStart, numFinish);
        int number = Integer.parseInt(substring,16);
        String stringStart = working.substring(0, index);
        String stringEnd   = working.substring(numFinish);
        working = stringStart + ((char)number) + stringEnd;
        index = working.indexOf("\\u");
    }
    return working;
}

標準Javaライブラリによって提供されるメソッドを再発明しようとします。純粋な実装を確認するだけですstackoverflow.com/a/39265921/1511077–
Evgeny Lebedev

1
@EvgenyLebedevに感謝します...標準ライブラリの方法は見栄えがよく、おそらく徹底的にテストされており、高く評価されています。
アンドリューパテ2018年

7

短いバージョン:

public static String unescapeJava(String escaped) {
    if(escaped.indexOf("\\u")==-1)
        return escaped;

    String processed="";

    int position=escaped.indexOf("\\u");
    while(position!=-1) {
        if(position!=0)
            processed+=escaped.substring(0,position);
        String token=escaped.substring(position+2,position+6);
        escaped=escaped.substring(position+6);
        processed+=(char)Integer.parseInt(token,16);
        position=escaped.indexOf("\\u");
    }
    processed+=escaped;

    return processed;
}

標準Javaライブラリによって提供されるメソッドを再発明しようとします。純粋な実装を確認するだけですstackoverflow.com/a/39265921/1511077–
Evgeny Lebedev

5

org.apache.commons.lang3ライブラリのStringEscapeUtilsは、3.6で非推奨になりました。

したがって、代わりに新しいcommons-textライブラリを使用できます。

compile 'org.apache.commons:commons-text:1.9'

OR

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-text</artifactId>
   <version>1.9</version>
</dependency>

コード例:

org.apache.commons.text.StringEscapeUtils.unescapeJava(escapedString);

4

あなたの質問からは完全には明らかではありませんが、ファイルの各行がファイル名であるファイルがあると言っていると思います。そして、各ファイル名は次のようなものです。

\u0048\u0065\u006C\u006C\u006F

言い換えれば、ファイル名のファイル内の文字は\u0048とになります。

もしそうなら、あなたが見ているものは期待されています。Javaは\uXXXX、ソースコード内の文字列リテラルのシーケンスのみを変換します(および格納されたPropertiesオブジェクトを読み取る場合)。あなたはファイルの内容を読んだとき、あなたは文字からなる文字列を持っています\u0048などといない文字列Hello

したがって、その文字列を解析して、、などの部分を抽出し00480065それらをcharsに変換して、それらから文字列を作成し、charその文字列をファイルを開くルーチンに渡す必要があります。



3

正規表現を使用して、私のバージョンを提供したかっただけです。

private static final String UNICODE_REGEX = "\\\\u([0-9a-f]{4})";
private static final Pattern UNICODE_PATTERN = Pattern.compile(UNICODE_REGEX);
...
String message = "\u0048\u0065\u006C\u006C\u006F World";
Matcher matcher = UNICODE_PATTERN.matcher(message);
StringBuffer decodedMessage = new StringBuffer();
while (matcher.find()) {
  matcher.appendReplacement(
      decodedMessage, String.valueOf((char) Integer.parseInt(matcher.group(1), 16)));
}
matcher.appendTail(decodedMessage);
System.out.println(decodedMessage.toString());

1

試してみてください

private static final Charset UTF_8 = Charset.forName("UTF-8");
private String forceUtf8Coding(String input) {return new String(input.getBytes(UTF_8), UTF_8))}

1

JsonObjectを使用して私が知っている簡単な方法の1つ:

try {
    JSONObject json = new JSONObject();
    json.put("string", myString);
    String converted = json.getString("string");

} catch (JSONException e) {
    e.printStackTrace();
}

1

これが私の解決策です...

                String decodedName = JwtJson.substring(startOfName, endOfName);

                StringBuilder builtName = new StringBuilder();

                int i = 0;

                while ( i < decodedName.length() )
                {
                    if ( decodedName.substring(i).startsWith("\\u"))
                    {
                        i=i+2;
                        builtName.append(Character.toChars(Integer.parseInt(decodedName.substring(i,i+4), 16)));
                        i=i+4;
                    }
                    else
                    {
                        builtName.append(decodedName.charAt(i));
                        i = i+1;
                    }
                };

標準Javaライブラリによって提供される標準メソッドの再発明を試みます。純粋な実装を確認してくださいstackoverflow.com/a/39265921/1511077–
Evgeny Lebedev

1

パフォーマンスが高く、エラーが発生しないソリューションを作成しました。

public static final String decode(final String in) {
    int p1 = in.indexOf("\\u");
    if (p1 < 0)
        return in;
    StringBuilder sb = new StringBuilder();
    while (true) {
        int p2 = p1 + 6;
        if (p2 > in.length()) {
            sb.append(in.subSequence(p1, in.length()));
            break;
        }
        try {
            int c = Integer.parseInt(in.substring(p1 + 2, p1 + 6), 16);
            sb.append((char) c);
            p1 += 6;
        } catch (Exception e) {
            sb.append(in.subSequence(p1, p1 + 2));
            p1 += 2;
        }
        int p0 = in.indexOf("\\u", p1);
        if (p0 < 0) {
            sb.append(in.subSequence(p1, in.length()));
            break;
        } else {
            sb.append(in.subSequence(p1, p0));
            p1 = p0;
        }
    }
    return sb.toString();
}

1

速い

 fun unicodeDecode(unicode: String): String {
        val stringBuffer = StringBuilder()
        var i = 0
        while (i < unicode.length) {
            if (i + 1 < unicode.length)
                if (unicode[i].toString() + unicode[i + 1].toString() == "\\u") {
                    val symbol = unicode.substring(i + 2, i + 6)
                    val c = Integer.parseInt(symbol, 16)
                    stringBuffer.append(c.toChar())
                    i += 5
                } else stringBuffer.append(unicode[i])
            i++
        }
        return stringBuffer.toString()
    }

0

実際、私はいくつかのユーティリティを含むオープンソースライブラリを作成しました。それらの1つは、Unicodeシーケンスを文字列に変換することです。とても便利だと思いました。Unicodeコンバータに関するこのライブラリに関する記事からの引用は次のとおりです。

クラスStringUnicodeEncoderDecoderには、文字列(任意の言語)をUnicode文字のシーケンスに(またはその逆に)変換できるメソッドがあります。たとえば、文字列「HelloWorld」はに変換されます

"\ u0048 \ u0065 \ u006c \ u006c \ u006f \ u0020 \ u0057 \ u006f \ u0072 \ u006c \ u0064"

復元される可能性があります。

これは、ライブラリにあるユーティリティと、ライブラリでそれを使用する方法を説明する記事全体へのリンクです。MavenアーティファクトまたはGithubからのソースとして入手できます。とても使いやすいです。スタックトレースフィルタリング、サイレント文字列解析Unicodeコンバーター、バージョン比較を備えたオープンソースJavaライブラリ


0

Java 9以降では、Matcherクラスの新しいreplaceAllメソッドを使用できます。

private static final Pattern UNICODE_PATTERN = Pattern.compile("\\\\u([0-9A-Fa-f]{4})");

public static String unescapeUnicode(String unescaped) {
    return UNICODE_PATTERN.matcher(unescaped).replaceAll(r -> String.valueOf((char) Integer.parseInt(r.group(1), 16)));
}

public static void main(String[] args) {
    String originalMessage = "\\u0048\\u0065\\u006C\\u006C\\u006F World";
    String unescapedMessage = unescapeUnicode(originalMessage);
    System.out.println(unescapedMessage);
}

私は終わっこのアプローチの主な利点と考えていunescapeJavaによってStringEscapeUtilsトン\ nまたは\のように(後者の変換は、すべてのJavaの文字をエスケープするので、(余分なライブラリを使用しない以外は)(あなたが望むなら)あなたが唯一のUnicode文字を変換することができるということです)。すべてのエスケープ文字を変換したい場合は、ライブラリが本当に最良のオプションです。


0

@NominSim他の文字があるかもしれないので、長さで検出する必要があります。

private String forceUtf8Coding(String str) {
    str = str.replace("\\","");
    String[] arr = str.split("u");
    StringBuilder text = new StringBuilder();
    for(int i = 1; i < arr.length; i++){
        String a = arr[i];
        String b = "";
        if (arr[i].length() > 4){
            a = arr[i].substring(0, 4);
            b = arr[i].substring(4);
        }
        int hexVal = Integer.parseInt(a, 16);
        text.append((char) hexVal).append(b);
    }
    return text.toString();
}

0

UnicodeUnescaperからorg.apache.commons:commons-textも許容されます。

new UnicodeUnescaper().translate("\u0048\u0065\u006C\u006C\u006F World") 戻り値 "Hello World"


-1

これを実現する別の方法はchars()、Java 9で導入されたものを利用することです。これを使用して文字を反復処理し、代理コードポイントにマップされるすべての文字が解釈されずに渡されるようにすることができます。これは次のように使用できます:-

String myString = "\u0048\u0065\u006C\u006C\u006F World";
myString.chars().forEach(a -> System.out.print((char)a));
// would print "Hello World"

-1

回答の多くが「補足文字」の問題に対応していないことがわかりました。これをサポートする正しい方法は次のとおりです。サードパーティのライブラリはなく、純粋なJava実装です。

http://www.oracle.com/us/technologies/java/supplementary-142654.html

public static String fromUnicode(String unicode) {
    String str = unicode.replace("\\", "");
    String[] arr = str.split("u");
    StringBuffer text = new StringBuffer();
    for (int i = 1; i < arr.length; i++) {
        int hexVal = Integer.parseInt(arr[i], 16);
        text.append(Character.toChars(hexVal));
    }
    return text.toString();
}

public static String toUnicode(String text) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < text.length(); i++) {
        int codePoint = text.codePointAt(i);
        // Skip over the second char in a surrogate pair
        if (codePoint > 0xffff) {
            i++;
        }
        String hex = Integer.toHexString(codePoint);
        sb.append("\\u");
        for (int j = 0; j < 4 - hex.length(); j++) {
            sb.append("0");
        }
        sb.append(hex);
    }
    return sb.toString();
}

@Test
public void toUnicode() {
    System.out.println(toUnicode("😊"));
    System.out.println(toUnicode("🥰"));
    System.out.println(toUnicode("Hello World"));
}
// output:
// \u1f60a
// \u1f970
// \u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064

@Test
public void fromUnicode() {
    System.out.println(fromUnicode("\\u1f60a"));
    System.out.println(fromUnicode("\\u1f970"));
    System.out.println(fromUnicode("\\u0048\\u0065\\u006c\\u006c\\u006f\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064"));
}
// output:
// 😊
// 🥰
// Hello World

次のように、文字列内にUnicode以外の文字が含まれている場合は機能しません:href = \ u0022 \ / en \ / blog \ / d-day-protecting-europe-its-demons \ u0022 \ u003E \ n
MohsenAbasi19年

-1

Kotlinのソリューション:

val sourceContent = File("test.txt").readText(Charset.forName("windows-1251"))
val result = String(sourceContent.toByteArray())

Kotlinは、デフォルトのエンコーディングとしてどこでもUTF-8を使用します。

メソッドにtoByteArray()はデフォルトの引数があります- Charsets.UTF_8


それは、提案者のbytearray-wayで「変換」できないコンテンツの実際の例がなければ答えではありません。あなたはそれを提供できますか?
エフゲニーレベデフ2018

String(string.toByteArray())文字通り何も達成しません。
rustyx

@rustyxメソッドにtoByteArray()はデフォルトの引数がありますCharsets.UTF_8。次に、必要なエンコーディングを使用してbytearrayから文字列を作成します。今日はwindows-1251utf-8でテストしましたが、動作します。また、バイトレベルで比較しました:)
Evgeny Lebedev

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.