Cách chuyển đổi một chuỗi có bảng mã Unicode thành một chuỗi các chữ cái


82

Tôi có một chuỗi với các tự Unicode thoát \uXXXXvà tôi muốn chuyển nó thành các ký tự Unicode thông thường. Ví dụ:

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

nên trở thành

"Hello World"

Tôi biết rằng khi tôi in chuỗi đầu tiên, nó đã hiển thị Hello world. Vấn đề của tôi là tôi đọc tên tệp từ một tệp, sau đó tôi tìm kiếm chúng. Tên tệp trong tệp được thoát bằng mã hóa Unicode và khi tôi tìm kiếm tệp, tôi không thể tìm thấy chúng, vì nó tìm kiếm tệp có \uXXXXtên của nó.


Bạn chắc chắn? Bạn không cho rằng các ký tự chỉ đơn giản được in ra khi Unicode thoát ra?
Hot Licks

5
\u0048 H - chúng là một và giống nhau. Các chuỗi trong Java là Unicode.
Hot Licks

Tôi đoán sự cố có thể xảy ra với java của tôi với api unix - chuỗi tôi nhận được giống như vậy \ u3123 \ u3255_file_name.txt. Và java đừng che đậy điều đó.
SharonBL

3
UTF-8 một mã hóa unicode.
Pavel Radzivilovsky

5
Đây không phải là câu trả lời cho câu hỏi của bạn nhưng hãy để tôi làm rõ sự khác biệt giữa Unicode và UTF-8, điều mà nhiều người có vẻ bối rối. Unicode là một đặc biệt one-to-one ánh xạ giữa các nhân vật như chúng ta biết họ ( a, b, $, £, vv) để các số nguyên. Ví dụ: ký hiệu Ađược cho là số 65 và \nlà 10. Điều này không liên quan gì đến cách biểu thị chuỗi hoặc ký tự trên đĩa hoặc trong tệp văn bản. UTF-8 là một đặc tả kỹ thuật (tức là mã hóa) về cách các số nguyên này (tức là các ký hiệu) được biểu diễn dưới dạng byte (chuỗi bit) để chúng có thể được viết và đọc rõ ràng từ một tệp.
DustByte

Câu trả lời:


48

Về mặt kỹ thuật làm:

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

tự động chuyển đổi nó thành "Hello World", vì vậy tôi giả sử bạn đang đọc trong chuỗi từ một số tệp. Để chuyển đổi nó thành "Hello", bạn sẽ phải phân tích cú pháp văn bản thành các chữ số unicode riêng biệt, (lấy \uXXXXvà chỉ lấy XXXX), sau đó làm Integer.ParseInt(XXXX, 16)để nhận giá trị hex và sau đó viết hoa charđể lấy ký tự thực.

Chỉnh sửa: Một số mã để thực hiện điều này:

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

Có vẻ đó là giải pháp. Bạn có ý tưởng về cách tôi có thể làm điều đó trong java - tôi có thể làm điều đó với String.replaceAll hoặc những thứ tương tự không?
SharonBL

@SharonBL Tôi đã cập nhật một số mã, ít nhất sẽ cung cấp cho bạn ý tưởng về nơi bắt đầu.
NominSim

2
Cảm ơn rất nhiều vì sự giúp đỡ của bạn! Tôi cũng đã tìm thấy một giải pháp khác cho điều đó: String s = StringEscapeUtils.unescapeJava ("\\ u20ac \\ n"); nó thực hiện công việc!
SharonBL

2
cố gắng phát minh lại các phương pháp được cung cấp bởi Thư viện Java tiêu chuẩn. chỉ cần kiểm tra thực hiện tinh khiết stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

1
Tôi luôn ngạc nhiên khi một câu trả lời " phát minh lại bánh xe " nhận được nhiều phiếu bầu như vậy.
Pedro Lobito

92

Các Apache Commons Lang StringEscapeUtils.unescapeJava () có thể giải mã nó đúng cách.

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

Chuỗi sJava = "\ u0048 \\ u0065 \ u006C \ u006C \ u006F"; -----> Vui lòng thực hiện thay đổi đơn giản.
Shreyansh Shah

29

Bạn có thể sử dụng StringEscapeUtilstừ Apache Commons Lang , tức là:

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


5
sau khi thêm phần phụ thuộc vào build.gradle: compile 'commons-lang: commons-lang: 2.6' ở trên hoạt động tốt.
Joseph Mekwan

8

Phương thức đơn giản này sẽ hoạt động đối với hầu hết các trường hợp, nhưng sẽ đi lên trên một cái gì đó như "u005Cu005C" sẽ giải mã thành chuỗi "\ u0048" nhưng thực sự sẽ giải mã "H" khi truyền đầu tiên tạo ra "\ u0048" là chuỗi hoạt động sau đó được xử lý lại bởi vòng lặp 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;
}

cố gắng phát minh lại các phương pháp được cung cấp bởi Thư viện Java tiêu chuẩn. chỉ cần kiểm tra thực hiện tinh khiết stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

1
Cảm ơn @EvgenyLebedev ... cách thư viện tiêu chuẩn có vẻ tốt và có lẽ đã được kiểm tra kỹ lưỡng, được đánh giá cao.
andrew pate

7

Phiên bản ngắn hơn:

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

cố gắng phát minh lại các phương pháp được cung cấp bởi Thư viện Java tiêu chuẩn. chỉ cần kiểm tra triển khai thuần túy stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

5

StringEscapeUtils từ thư viện org.apache.commons.lang3 không được chấp nhận kể từ ngày 3.6.

Vì vậy, bạn có thể sử dụng thư viện văn bản commons mới của họ thay thế:

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

OR

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

Mã ví dụ:

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

4

Câu hỏi của bạn không hoàn toàn rõ ràng, nhưng tôi giả sử bạn nói rằng bạn có một tệp trong đó mỗi dòng của tệp đó là một tên tệp. Và mỗi tên tệp là như thế này:

\u0048\u0065\u006C\u006C\u006F

Nói cách khác, các nhân vật trong các tập tin của tên tập tin là \, u, 0, 0, 4, 8và vân vân.

Nếu vậy, những gì bạn đang thấy là mong đợi. Java chỉ dịch \uXXXXcác chuỗi theo chuỗi ký tự trong mã nguồn (và khi đọc trong Propertiescác đối tượng được lưu trữ ). Khi bạn đọc những nội dung quý vị nộp bạn sẽ có một chuỗi gồm các nhân vật \, u, 0, 0, 4, 8và vân vân và không dây Hello.

Vì vậy, bạn sẽ cần phải phân tích cú pháp chuỗi đó để trích xuất các phần 0048, 0065v.v. và sau đó chuyển đổi chúng thành chars và tạo một chuỗi từ các chars đó và sau đó chuyển chuỗi đó vào quy trình mở tệp.



3

Chỉ muốn đóng góp phiên bản của tôi, sử dụng regex:

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

thử

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

một cách dễ dàng mà tôi biết bằng cách sử dụng JsonObject:

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

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

1

Đây là giải pháp của tôi ...

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

cố gắng phát minh lại các phương pháp tiêu chuẩn được cung cấp bởi Thư viện Java tiêu chuẩn. chỉ cần kiểm tra triển khai thuần túy stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

1

Tôi đã viết một giải pháp hiệu quả và chống lỗi:

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

Nhanh

 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

Trên thực tế, tôi đã viết một thư viện Mã nguồn mở có chứa một số tiện ích. Một trong số đó là chuyển đổi chuỗi Unicode thành Chuỗi và ngược lại. Tôi tìm thấy nó rất hữu ích. Đây là trích dẫn từ bài viết về thư viện này về bộ chuyển đổi Unicode:

Class StringUnicodeEncoderDecoder có các phương thức có thể chuyển đổi một Chuỗi (bằng bất kỳ ngôn ngữ nào) thành một chuỗi các ký tự Unicode và ngược lại. Ví dụ: Chuỗi "Hello World" sẽ được chuyển đổi thành

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

và có thể được khôi phục trở lại.

Đây là liên kết đến toàn bộ bài viết giải thích thư viện có những Tiện ích gì và cách sử dụng thư viện. Nó có sẵn dưới dạng tạo tác Maven hoặc nguồn từ Github. Nó rất dễ sử dụng. Thư viện mã nguồn mở Java với tính năng lọc theo dõi ngăn xếp, trình chuyển đổi Unicode phân tích cú pháp Silent String và so sánh phiên bản


0

Đối với Java 9+, bạn có thể sử dụng phương thức ReplaceAll mới của lớp Matcher .

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

Tôi tin rằng ưu điểm chính của phương pháp này so với unescapeJava của StringEscapeUtils (ngoài việc không sử dụng thêm thư viện) là bạn chỉ có thể chuyển đổi các ký tự unicode (nếu bạn muốn), vì sau này chuyển đổi tất cả các ký tự Java thoát ra (như \ n hoặc \ t ). Nếu bạn muốn chuyển đổi tất cả các ký tự thoát thì thư viện thực sự là lựa chọn tốt nhất.


0

@NominSim Có thể có ký tự khác, vì vậy tôi nên phát hiện theo độ dài.

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

UnicodeUnescapertừ org.apache.commons:commons-textcũng có thể chấp nhận được.

new UnicodeUnescaper().translate("\u0048\u0065\u006C\u006C\u006F World") trả lại "Hello World"


-1

Một cách thay thế để thực hiện điều này có thể là sử dụng chars()Java 9 đã được giới thiệu, điều này có thể được sử dụng để lặp lại các ký tự đảm bảo bất kỳ ký tự nào ánh xạ tới điểm mã thay thế đều được chuyển qua không thông dịch. Điều này có thể được sử dụng như: -

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

-1

Tôi thấy rằng nhiều câu trả lời không đề cập đến vấn đề "Nhân vật bổ sung". Đây là cách chính xác để hỗ trợ nó. Không có thư viện của bên thứ ba, triển khai Java thuần túy.

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

Không hoạt động khi không có ký tự unicode bên trong chuỗi, chẳng hạn như: href = \ u0022 \ / en \ / blog \ / d-day-protect-europe-its-devil \ u0022 \ u003E \ n
Mohsen Abasi

-1

Giải pháp cho Kotlin:

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

Kotlin sử dụng UTF-8 ở mọi nơi làm mã hóa mặc định.

Phương thức toByteArray()có đối số mặc định - Charsets.UTF_8.


nó không phải là một câu trả lời nếu không có các ví dụ thực tế về nội dung không thể được "chuyển đổi" với bytearray-way gợi ý. bạn có thể cung cấp nó?
Evgeny Lebedev

String(string.toByteArray())không đạt được gì theo nghĩa đen.
gỉyx

@rustyx Phương thức toByteArray()có đối số mặc định với Charsets.UTF_8. Sau đó, bạn tạo một chuỗi từ bytearray với mã hóa bắt buộc. Tôi đã thử nghiệm hôm nay với windows-1251utf-8, nó hoạt động. Ngoài ra, tôi đã so sánh ở mức byte :)
Evgeny Lebedev

@rustyx đây là ý chính dành cho bạn - gist.github.com/lebe-dev/31e31a3399c7885e298ed86810504676
Evgeny Lebedev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.