Unicode kodlamasına sahip bir dizeyi bir harf dizisine dönüştürme


84

Kaçan Unicode karakterleri olan bir dizem var \uXXXXve bunu normal Unicode harflerine dönüştürmek istiyorum. Örneğin:

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

olmalı

"Hello World"

İlk dizeyi yazdırdığımda zaten gösterdiğini biliyorum Hello world. Sorunum, bir dosyadan dosya adlarını okuduktan sonra onları ararım. Dosyadaki dosya adları Unicode kodlaması ile önceleniyor ve dosyaları aradığımda \uXXXX, adında bir dosya aradığı için onları bulamıyorum .


Eminsin? Unicode çıkışları olarak karakterlerin basitçe yazdırıldığını düşünmüyor musunuz?
Hot Licks

5
\u0048 olduğunu H - onlar bir ve aynıdır. Java'daki dizeler Unicode'dadır.
Hot Licks

Sanırım sorun java'mda api'yi unix yapmakta olabilir - aldığım dizge \ u3123 \ u3255_file_name.txt gibi bir şey. Ve java onu gizlemez.
SharonBL

3
UTF-8 olduğu bir Unicode kodlaması.
Pavel Radzivilovsky

5
Bu, sorunuzun cevabı değil, ancak Unicode ve UTF-8 arasındaki farkı açıklığa kavuşturmama izin verin, ki bu birçok insan karıştırıyor gibi görünüyor. Unicode belirli olan bire-bir biz (onları bildiği gibi karakterler arasında haritalama a, b, $, £tamsayılar için, vs). Örneğin, sembole A65 numara verilir ve \n10'dur. Bunun dizelerin veya karakterlerin diskte veya bir metin dosyasında nasıl temsil edildiğiyle hiçbir ilgisi yoktur. UTF-8, bu tam sayıların (yani sembollerin) baytlar (bit dizgileri) olarak nasıl temsil edildiğinin bir spesifikasyonudur (yani kodlama), böylece açıkça yazılabilmeleri ve bir dosyadan okunabilmeleri için.
DustByte

Yanıtlar:


49

Teknik olarak yapıyor:

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

otomatik olarak 'a dönüştürür "Hello World", bu yüzden dizeyi bir dosyadan okuduğunuzu varsayıyorum. Bunu "Merhaba" ya dönüştürmek için, metni ayrı unicode rakamlarına ayrıştırmanız, (al \uXXXXve sadece al XXXX) sonra Integer.ParseInt(XXXX, 16)onaltılık bir değer elde etmeniz ve ardından chargerçek karakteri elde etmek için bunu büyük harflerle yazmanız gerekir .

Düzenleme: Bunu gerçekleştirmek için bazı kodlar:

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

Çözüm bu gibi görünüyor. Java'da nasıl yapabileceğime dair bir fikriniz var mı - String.replaceAll veya bunun gibi bir şey ile yapabilir miyim?
SharonBL

@SharonBL Bazı kodlarla güncelledim, en azından nereden başlayacağınıza dair bir fikir vermeli.
NominSim

2
Yardımınız için çok teşekkür ederim! Ayrıca bunun için başka bir çözüm buldum: String s = StringEscapeUtils.unescapeJava ("\\ u20ac \\ n"); işi yapıyor!
SharonBL

2
Standart Java Kitaplığı tarafından sağlanan yöntemleri yeniden keşfetme girişiminde bulunun. sadece saf uygulama stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

1
" Tekerleği yeniden icat " cevabının bu kadar çok oy alması beni hep şaşırtıyor .
Pedro Lobito

93

Apache Commons Lang StringEscapeUtils.unescapeJava () düzgün bir şekilde çözebilir.

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

String sJava = "\ u0048 \\ u0065 \ u006C \ u006C \ u006F"; -----> Lütfen basit bir değişiklik yapın.
Shreyansh Shah

30

Sen kullanabilirsiniz StringEscapeUtilsgelen Apache Commons Lang , yani:

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


5
build.gradle: compile 'commons-lang: commons-lang: 2.6' içine bağımlılık ekledikten sonra düzgün çalışıyor.
Joseph Mekwan

8

Bu basit yöntem çoğu durumda işe yarayacaktır, ancak "u005Cu005C" gibi bir şeye takılıp, "\ u0048" dizesini çözmesi gerekir, ancak ilk geçiş "\ u0048" öğesini çalışma dizesi olarak ürettiğinden aslında "H" kodunu çözer. sonra while döngüsü tarafından yeniden işlenir.

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

Standart Java Kitaplığı tarafından sağlanan yöntemleri yeniden keşfetme girişiminde bulunun. sadece saf uygulama stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

1
Teşekkürler @EvgenyLebedev ... standart kütüphane yolu iyi görünüyor ve muhtemelen kapsamlı bir şekilde test edildi, çok takdir edildi.
andrew pate

7

Daha kısa versiyon:

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

Standart Java Kitaplığı tarafından sağlanan yöntemleri yeniden keşfetme girişiminde bulunun. sadece saf uygulama stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

5

Org.apache.commons.lang3 kitaplığındaki StringEscapeUtils 3.6 itibarıyla kullanımdan kaldırılmıştır .

Böylece bunun yerine yeni ortak metin kitaplıklarını kullanabilirsiniz :

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

OR

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

Örnek kod:

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

4

Sorunuz tamamen açık değil, ancak bu dosyanın her satırının bir dosya adı olduğu bir dosyanız olduğunu varsayıyorum. Ve her dosya adı şuna benzer:

\u0048\u0065\u006C\u006C\u006F

Başka bir deyişle, dosya adlarının dosyadaki karakterlerdir \, u, 0, 0, 4, 8ve bu kadar.

Eğer öyleyse, görmeniz beklenen şeydir. Java, yalnızca \uXXXXkaynak kodda (ve depolanan Propertiesnesnelerde okurken) dizelerdeki dizileri çevirir . Eğer içeriğini okuduğunuzda size karakterden oluşan bir dize olacaktır dosya \, u, 0, 0, 4, 8vb ve değil dize Hello.

Eğer ayıklamak için bu dizeyi ayrıştırmak gerekir Yani 0048, 0065vb parçaları ve sonra onları dönüştürmek chars ve olanlardan bir dize yapmak chars ve daha sonra dosyayı açar rutin olduğunu dize geçirir.



3

Sadece normal ifadeyi kullanarak sürümüme katkıda bulunmak istedim:

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

2

Performanslı ve hatasız bir çözüm yazdım:

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

Deneyin

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 kullanarak bildiğim kolay bir yol:

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

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

1

İşte benim çözümüm ...

                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 tarafından sağlanan standart yöntemleri yeniden keşfetmeyi deneyin. sadece saf uygulama stackoverflow.com/a/39265921/1511077
Evgeny Lebedev

1

Hızlı

 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

Aslında, bazı yardımcı programları içeren bir Açık Kaynak kitaplığı yazdım. Bunlardan biri, Unicode dizisini String'e ve tersi yönde dönüştürmektir. Bunu çok kullanışlı buldum. Unicode dönüştürücü ile ilgili bu kitaplık hakkındaki makaleden alıntı:

Sınıf StringUnicodeEncoderDecoder, bir String'i (herhangi bir dilde) Unicode karakterleri dizisine ve bunun tersine dönüştürebilen yöntemlere sahiptir. Örneğin, "Hello World" dizesi,

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

ve geri yüklenebilir.

Kitaplığın hangi Yardımcı Programlara sahip olduğunu ve kitaplığın onu nasıl kullanacağını açıklayan tüm makalenin bağlantısı burada. Maven eseri olarak veya Github'dan kaynak olarak mevcuttur. Kullanımı çok kolaydır. Yığın izleme filtrelemeli Açık Kaynak Java kitaplığı, Silent String ayrıştırma Unicode dönüştürücü ve Sürüm karşılaştırması


0

Java 9+ için, Matcher sınıfının yeni replaceAll yöntemini kullanabilirsiniz .

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

Ben üzerinden bu yaklaşımın en önemli avantajı inanıyoruz unescapeJava tarafından StringEscapeUtils (yanında ekstra bir kütüphane kullanarak değil) (isterseniz) tüm benzer \ n ya \ t (Java karakterleri kaçan ikincisi dönüştürür beri, yalnızca Unicode karakterleri dönüştürmek olduğunu ). Tüm kaçan karakterleri dönüştürmeyi tercih ederseniz, kitaplık gerçekten en iyi seçenektir.


0

@NominSim Başka bir karakter olabilir, bu yüzden uzunluğuna göre tespit etmeliyim.

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

UnicodeUnescaperdan org.apache.commons:commons-textda kabul edilebilir.

new UnicodeUnescaper().translate("\u0048\u0065\u006C\u006C\u006F World") İadeler "Hello World"


-1

Bunu başarmanın alternatif bir yolu, chars() Java 9 ile sunulanlardan yararlanmak olabilir, bu, bir vekil kod noktasına eşlenen herhangi bir karakterin yorumlanmadan geçirildiğinden emin olmak için karakterler üzerinde yineleme yapmak için kullanılabilir . Bu şu şekilde kullanılabilir: -

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

-1

Cevapların çoğunun "Ek Karakterler" konusuna değinmediğini buldum. İşte onu desteklemenin doğru yolu. Üçüncü taraf kitaplıkları yok, saf Java uygulaması.

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

Dize içinde unicode olmayan karakterler olduğunda çalışmaz, örneğin: href = \ u0022 \ / tr \ / blog \ / d-day-protect-europe-its-demonları \ u0022 \ u003E \ n
Mohsen Abasi

-1

Kotlin için Çözüm:

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

Kotlin, varsayılan kodlama olarak her yerde UTF-8 kullanır.

Yöntemin toByteArray()varsayılan bağımsız değişkeni var - Charsets.UTF_8.


Bu, önerici bytearray yolu ile "dönüştürülemeyen" gerçek içerik örnekleri olmadan bir cevap değildir. sağlayabilir misin
Evgeny Lebedev

String(string.toByteArray())tam anlamıyla hiçbir şey başaramaz.
rustyx

@rustyx Metodunun toByteArray()varsayılan argümanı var Charsets.UTF_8. Sonra gerekli kodlama ile bytearray'den bir dize oluşturursunuz. Bugün windows-1251utf-8 ile test yaptım , işe yarıyor. Ayrıca bayt düzeyinde karşılaştırma yaptım :)
Evgeny Lebedev

@rustyx işte size bir özet
Evgeny Lebedev
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.