유니 코드로 인코딩 된 문자열을 문자 문자열로 변환하는 방법


82

이스케이프 된 유니 코드 문자 가있는 문자열이 있는데 \uXXXX이를 일반 유니 코드 문자로 변환하고 싶습니다. 예를 들면 :

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

되어야한다

"Hello World"

첫 번째 문자열을 인쇄 할 때 이미 표시되는 것을 알고 Hello world있습니다. 내 문제는 파일에서 파일 이름을 읽은 다음 검색하는 것입니다. 파일의 파일 이름은 유니 코드 인코딩으로 이스케이프되고 파일을 검색 할 때 이름에있는 파일을 검색하기 때문에 파일을 찾을 수 없습니다 \uXXXX.


확실해? 문자가 단순히 유니 코드 이스케이프로 인쇄된다고 생각하지 않습니까?
Hot Licks

5
\u0048 입니다 H - 그들은 하나와 동일합니다. Java의 문자열은 유니 코드입니다.
Hot Licks

문제는 내 Java to Unix API에있을 수 있다고 생각합니다-내가 얻는 문자열은 \ u3123 \ u3255_file_name.txt와 같습니다. 그리고 자바는 그것을 은밀하지 않습니다.
SharonBL 2012-06-21

3
UTF-8 유니 코드 인코딩입니다.
Pavel Radzivilovsky

5
이것은 귀하의 질문에 대한 대답이 아니지만 많은 사람들이 혼란스러워하는 유니 코드와 UTF-8의 차이점을 명확히하겠습니다. 유니 코드는 특정입니다 일대일 우리는 (그들이 알고있는 문자 사이의 매핑 a, b, $, £정수로, 등). 예를 들어, 기호 A는 숫자 65이고 \n10입니다. 이것은 문자열이나 문자가 디스크 나 텍스트 파일에서 어떻게 표현되는지와 는 관련없습니다 . UTF-8은 이러한 정수 (예 : 기호)가 바이트 (비트 문자열)로 표현되는 방식에 대한 사양 (예 : 인코딩)이므로 파일에서 명확하게 쓰고 읽을 수 있습니다.
DustByte

답변:


48

기술적으로 수행 :

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

자동으로으로 변환 "Hello World"하므로 일부 파일의 문자열을 읽는다고 가정합니다. "Hello"로 변환하려면 텍스트를 별도의 유니 코드 숫자로 구문 분석해야합니다 (을 가져 와서 가져 오기만 \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-06-21

@SharonBL 나는 약간의 코드로 업데이트했는데, 적어도 어디에서 시작해야할지에 대한 아이디어를 제공해야합니다.
NominSim

2
도와 주셔서 감사합니다! 또 다른 해결책을 찾았습니다. String s = StringEscapeUtils.unescapeJava ( "\\ u20ac \\ n"); 작동합니다!
SharonBL

2
Standard Java Library에서 제공하는 메소드를 재발 명하려고합니다. 순수한 구현 확인 stackoverflow.com/a/39265921/1511077을
에브 게니 레베 데프

1
" 바퀴를 재발 명 "하는 답변이 너무 많은 표를 얻었을 때 저는 항상 놀랍 습니다.
Pedro Lobito 2018

92

아파치 코 몬즈 랭 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 샤

29

Apache Commons LangStringEscapeUtils 에서 사용할 수 있습니다 .

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


5
build.gradle에 의존성을 추가 한 후 : 위의 'commons-lang : commons-lang : 2.6'을 컴파일하면 정상적으로 작동합니다.
Joseph Mekwan

8

이 간단한 방법은 대부분의 경우에 작동하지만 문자열 "\ u0048"로 디코딩해야하지만 실제로 "H"를 디코딩하는 "u005Cu005C"와 같은 것을 넘어서서 첫 번째 패스가 작업 문자열로 "\ u0048"을 생성합니다. 그런 다음 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;
}

Standard Java Library에서 제공하는 메소드를 재발 명하려고합니다. 순수한 구현 확인 stackoverflow.com/a/39265921/1511077을
에브 게니 레베 데프

1
감사합니다 @EvgenyLebedev ... 표준 라이브러리 방식은 좋아 보이며 아마도 철저한 테스트를 거쳤으며 많은 평가를 받았습니다.
앤드류 머리

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;
}

Standard Java Library에서 제공하는 메소드를 재발 명하려고합니다. 순수한 구현 확인 stackoverflow.com/a/39265921/1511077을
에브 게니 레베 데프

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

즉, 파일 이름의 파일에있는 문자는 \, u, 0, 0, 4, 8과에 있도록.

그렇다면, 당신이보고있는 것이 예상됩니다. Java \uXXXX는 소스 코드의 문자열 리터럴의 시퀀스 만 변환 합니다 (저장된 Properties객체 에서 읽을 때 ). 당신이 내용을 읽을 때 당신이 문자로 구성된 문자열을해야합니다 파일 \, u, 0, 0, 4, 8등 및 하지 문자열 Hello.

따라서 해당 문자열을 구문 분석하여 0048, 0065등의 조각 을 추출한 다음 chars 로 변환하고 해당 chars 에서 문자열을 만든 다음 해당 문자열을 파일을 여는 루틴에 전달해야합니다.



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를 사용하는 한 가지 쉬운 방법 :

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;
                    }
                };

Standard Java Library에서 제공하는 표준 메소드를 재발 명하려고합니다. 순수한 구현 확인 stackoverflow.com/a/39265921/1511077을
에브 게니 레베 데프

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

사실 저는 일부 유틸리티를 포함하는 오픈 소스 라이브러리를 작성했습니다. 그중 하나는 유니 코드 시퀀스를 문자열로 변환하는 것입니다. 나는 그것이 매우 유용하다는 것을 알았습니다. 다음은 유니 코드 변환기에 대한이 라이브러리에 대한 기사의 인용문입니다.

StringUnicodeEncoderDecoder 클래스에는 문자열 (모든 언어)을 일련의 유니 코드 문자로 변환 할 수있는 메서드가 있으며 그 반대의 경우도 마찬가지입니다. 예를 들어 문자열 "Hello World"는 다음으로 변환됩니다.

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

다시 복원 될 수 있습니다.

다음은 라이브러리에있는 유틸리티와 라이브러리를 사용하는 방법을 설명하는 전체 문서에 대한 링크입니다. Maven 아티팩트 또는 Github의 소스로 사용할 수 있습니다. 사용하기 매우 쉽습니다. 스택 추적 필터링, 자동 문자열 구문 분석 유니 코드 변환기 및 버전 비교 기능이있는 오픈 소스 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);
}

나는 StringEscapeUtils의 unescapeJava비해 (추가 라이브러리를 사용하지 않는 것 외에) 이 접근 방식의 주요 장점은 유니 코드 문자 만 변환 할 수 있다는 것입니다 (원하는 경우). 후자는 모든 이스케이프 된 Java 문자 (예 : \ n 또는 \ t)를 변환하기 때문입니다. ). 모든 이스케이프 문자를 변환하려는 경우 라이브러리가 실제로 가장 좋은 옵션입니다.


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

UnicodeUnescaperfrom 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

문자열 내에 비 유니 코드 문자가있는 경우 작동하지 않음 : href = \ u0022 \ / en \ / blog \ / d-day-protecting-europe-its-demons \ u0022 \ u003E \ n
Mohsen Abasi

-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로 "변환"될 수없는 내용의 실제 예가없는 답변은 아닙니다. 제공 할 수 있습니까?
Evgeny Lebedev

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.