Zakoduj ciąg znaków do UTF-8


190

Mam ciąg znaków „ñ” i mam z tym pewne problemy. Muszę zakodować ten ciąg do kodowania UTF-8. Próbowałem w ten sposób, ale to nie działa:

byte ptext[] = myString.getBytes();
String value = new String(ptext, "UTF-8");

Jak zakodować ten ciąg do utf-8?


2
Nie jest jasne, co dokładnie próbujesz zrobić. Czy myString poprawnie zawiera znak ñ i masz problemy z konwersją go na tablicę bajtów (w takim przypadku zobacz odpowiedzi od Petera i Amira), czy też myString jest uszkodzony i próbujesz go naprawić (w takim przypadku zobacz odpowiedzi od Joachima i ja)?
Michael Borgwardt,

Muszę wysłać myString na serwer z kodowaniem utf-8 i muszę przekonwertować znak „ñ” na kodowanie utf-8.
Alex

1
Cóż, jeśli ten serwer oczekuje UTF-8, to musisz go wysłać to bajty, a nie ciąg. Tak więc, zgodnie z odpowiedzią Piotra, określ kodowanie w pierwszej linii i upuść drugą linię.
Michael Borgwardt,

@Michael: Zgadzam się, że nie jest jasne, jaki jest prawdziwy zamiar. Wydaje się, że jest wiele pytań, w których ludzie próbują jawnie przekształcić ciągi znaków i bajty, zamiast pozwolić im {In,Out}putStream{Read,Writ}ersto zrobić. Zastanawiam się dlaczego?
tchrist 21.04.11

1
@Michael: Dzięki, przypuszczam, że to ma sens. Ale to także sprawia, że ​​jest trudniej, niż musi być, prawda? Nie przepadam za językami, które działają w ten sposób, dlatego staraj się unikać współpracy z nimi. Myślę, że model ciągów znaków zamiast bajtów w Javie sprawia, że ​​jest o wiele łatwiej. Perl i Python dzielą również model „wszystko jest ciągami Unicode”. Tak, we wszystkich trzech nadal możesz dostać bajty, jeśli pracujesz nad tym, ale w praktyce wydaje się rzadkie, że naprawdę musisz: to dość niski poziom. Poza tym czujesz, jakbyś pędził kota w złym kierunku, jeśli wiesz, co mam na myśli. :)
tchrist 21.04.11

Odpowiedzi:


140

String obiekty w Javie używają kodowania UTF-16, którego nie można modyfikować.

Jedyne, co może mieć inne kodowanie, to byte[]. Więc jeśli potrzebujesz danych UTF-8, potrzebujesz byte[]. Jeśli masz plik, Stringktóry zawiera nieoczekiwane dane, oznacza to, że problem występuje w pewnym wcześniejszym miejscu, które nieprawidłowo przekonwertowało niektóre dane binarne na String(tj. Używało nieprawidłowego kodowania).


92
Mówiąc technicznie, bajt [] nie ma żadnego kodowania. Kodowanie w tablicy bajtów PLUS może dać ci ciąg znaków.
Peter Štibraný,

1
@Peter: true. Ale dołączenie do niego kodowania ma sens byte[], ale nie ma sensu String(chyba że kodowanie to UTF-16, w którym to przypadku ma sens, ale nadal zawiera niepotrzebne informacje).
Joachim Sauer,

4
String objects in Java use the UTF-16 encoding that can't be modified. Czy masz oficjalne źródło tego cytatu?
Ahmad Hajjar

@AhmadHajjar docs.oracle.com/javase/10/docs/api/java/lang/… : „Platforma Java używa reprezentacji UTF-16 w tablicach znaków oraz w klasach String i StringBuffer.”
Maxi Gis,

173

Co powiesz na korzystanie

ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(myString)

Zobacz moją dyskusję z Peterem. Ale jeśli jego założenie dotyczące pytania jest słuszne, twoje rozwiązanie nadal nie byłoby pomysłem, ponieważ zwraca ByteBuffer.
Michael Borgwardt,

8
Ale jak uzyskać zakodowany ciąg? zwraca ByteBuffer
Alex

7
@Alex: nie jest możliwe posiadanie napisu Java zakodowanego w UTF-8. Chcesz bajtów, więc albo użyć ByteBuffer bezpośrednio (może być nawet najlepszym rozwiązaniem, jeśli twoim celem jest, aby wysłać go poprzez zbiór sieci) lub tablicy call () na to, aby uzyskać byte []
Michael Borgwardt

2
Coś innego, co może być pomocne, to użycie wyliczenia Guawa Charsets.UTF_8 zamiast ciągu, który może zgłosić wyjątek UnsupportedEncodingException. String -> bajtów: myString.getBytes(Charsets.UTF_8)i bajty -> String: new String(myByteArray, Charsets.UTF_8).
laughing_man

24
Jeszcze lepiej, użyj StandardCharsets.UTF_8. Dostępne w Javie 1.7+.
Kat

81

W Javie 7 możesz używać:

import static java.nio.charset.StandardCharsets.*;

byte[] ptext = myString.getBytes(ISO_8859_1); 
String value = new String(ptext, UTF_8); 

Ma to tę zaletę getBytes(String), że nie deklaruje throws UnsupportedEncodingException.

Jeśli używasz starszej wersji Java, możesz samodzielnie zadeklarować stałe zestawu znaków:

import java.nio.charset.Charset;

public class StandardCharsets {
    public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
    public static final Charset UTF_8 = Charset.forName("UTF-8");
    //....
}

2
To jest właściwa odpowiedź. Jeśli ktoś chce użyć typu danych ciągu, może użyć go we właściwym formacie. Pozostałe odpowiedzi wskazują na typ sformatowany w bajtach.
Neeraj Shukla,

Działa w 6. Dzięki.
Itsik Mauyhas,

Również dla mnie poprawna odpowiedź. Jedną rzeczą jednak było to, że gdy użyłem powyższego, niemiecki znak zmienił się na? Więc użyłem tego: byte [] ptext = myString.getBytes (UTF_8); Wartość ciągu = nowy Ciąg (ptext, UTF_8); To działało dobrze.
Farhan Hafeez

3
Próbka kodu nie ma sensu. Jeśli najpierw przekonwertujesz na ISO-8859-1, to ta tablica bajtów nie jest UTF-8, więc następny wiersz jest całkowicie niepoprawny. Będzie pracować dla ciągów ASCII, oczywiście, ale to może równie dobrze można zrobić prosty kopię: String value = new String(myString);.
Alexis Wilke,

76

Użyj byte[] ptext = String.getBytes("UTF-8");zamiast getBytes(). getBytes()używa tak zwanego „domyślnego kodowania”, którym może nie być UTF-8.


9
@Michael: najwyraźniej ma problem z pobieraniem bajtów z ciągu. Dlaczego getBytes (kodowanie) nie ma sensu? Myślę, że druga linia jest po to, by sprawdzić, czy może ją przekonwertować.
Peter Štibraný,

1
Interpretuję go jako mający zepsuty ciąg znaków i próbujący go „naprawić” poprzez konwersję na bajty i wstecz (częste nieporozumienie). Nic nie wskazuje na to, że druga linia po prostu sprawdza wynik.
Michael Borgwardt,

@Michael, nie, nie ma, to tylko moja interpretacja. Twoja jest po prostu inna.
Peter Štibraný,

1
@Peter: masz rację, potrzebowalibyśmy wyjaśnienia od Alexa, co on naprawdę ma na myśli. Nie można cofnąć głosowania negatywnego, chyba że odpowiedź zostanie zredagowana ...
Michael Borgwardt,

33

Łańcuch Java jest wewnętrznie zawsze zakodowany w UTF-16 - ale naprawdę powinieneś o tym pomyśleć w ten sposób: kodowanie jest sposobem na translację między ciągami i bajtami.

Więc jeśli masz problem z kodowaniem, do czasu, gdy masz String, jest już za późno, aby to naprawić. Musisz naprawić miejsce, w którym tworzysz ten ciąg z pliku, bazy danych lub połączenia sieciowego.


1
Powszechnym błędem jest przekonanie, że łańcuchy są wewnętrznie kodowane jako UTF-16. Zwykle są, ale jeśli jest to tylko specyficzny dla implementacji szczegół klasy String. Ponieważ wewnętrzne przechowywanie danych znakowych nie jest dostępne za pośrednictwem publicznego interfejsu API, konkretna implementacja ciągu może zdecydować o użyciu dowolnego innego kodowania.
jarnbjo,

4
@jarnbjo: Interfejs API wyraźnie stwierdza „Ciąg znaków reprezentuje ciąg znaków w formacie UTF-16”. Używanie czegokolwiek innego jako formatu wewnętrznego byłoby wysoce nieefektywne, a wszystkie rzeczywiste implementacje, które znam, używają UTF-16 wewnętrznie. Więc jeśli nie możesz przytoczyć takiego, który tego nie robi, angażujesz się w dość absurdalny podział włosów.
Michael Borgwardt,

Czy absurdalne jest rozróżnienie między publicznym dostępem a wewnętrzną reprezentacją struktur danych?
jarnbjo,

6
JVM (o ile w ogóle dotyczy maszyny wirtualnej) używa UTF-8 do kodowania ciągów znaków, np. W plikach klas. Implementacja java.lang.String jest oddzielona od JVM i mógłbym łatwo zaimplementować klasę za pomocą dowolnego innego kodowania dla wewnętrznej reprezentacji, jeśli jest to naprawdę konieczne, aby zdać sobie sprawę, że twoja odpowiedź jest nieprawidłowa. Używanie UTF-16 jako formatu wewnętrznego jest w większości przypadków również wysoce nieefektywne, jeśli chodzi o zużycie pamięci i nie rozumiem, dlaczego np. Implementacje Java dla sprzętu wbudowanego nie zoptymalizowałyby się pod kątem pamięci zamiast wydajności.
jarnbjo,

1
@jarnbjo: I jeszcze raz: dopóki nie możesz podać konkretnego przykładu JVM, którego standardowa implementacja API używa wewnętrznie czegoś innego niż UTF-16 do implementacji ciągów, moja instrukcja jest poprawna. I nie, klasa String nie jest tak naprawdę oddzielona od JVM z powodu rzeczy takich jak intern () i stała pula.
Michael Borgwardt,

22

Możesz spróbować w ten sposób.

byte ptext[] = myString.getBytes("ISO-8859-1"); 
String value = new String(ptext, "UTF-8"); 

1
Wariowałam. Dziękujemy, aby najpierw pobrać bajty w „ISO-8859-1”.
Gian Gomen

2
To jest źle. Jeśli Twój ciąg znaków zawiera znaki Unicode, konwersja go na 8859-1 spowoduje wygenerowanie wyjątku lub, co gorsza, da ci niepoprawny ciąg znaków (być może ciąg bez tych znaków o kodzie 0x100 i więcej).
Alexis Wilke,

12

Po chwili przeszedłem przez ten problem i udało mi się go rozwiązać w następujący sposób

najpierw muszę zaimportować

import java.nio.charset.Charset;

Potem musiałem zadeklarować stałą w użyciu UTF-8iISO-8859-1

private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final Charset ISO = Charset.forName("ISO-8859-1");

Następnie mógłbym użyć go w następujący sposób:

String textwithaccent="Thís ís a text with accent";
String textwithletter="Ñandú";

text1 = new String(textwithaccent.getBytes(ISO), UTF_8);
text2 = new String(textwithletter.getBytes(ISO),UTF_8);

1
idealne rozwiązanie.
Tunde Pizzle

9
String value = new String(myString.getBytes("UTF-8"));

i jeśli chcesz czytać z pliku tekstowego z kodowaniem „ISO-8859-1”:

String line;
String f = "C:\\MyPath\\MyFile.txt";
try {
    BufferedReader br = Files.newBufferedReader(Paths.get(f), Charset.forName("ISO-8859-1"));
    while ((line = br.readLine()) != null) {
        System.out.println(new String(line.getBytes("UTF-8")));
    }
} catch (IOException ex) {
    //...
}

2

Używam poniższego kodu do kodowania znaku specjalnego poprzez określenie formatu kodowania.

String text = "This is an example é";
byte[] byteText = text.getBytes(Charset.forName("UTF-8"));
//To get original string from byte.
String originalString= new String(byteText , "UTF-8");

2

Szybki przewodnik krok po kroku, jak skonfigurować domyślne kodowanie NetBeans UTF-8. W rezultacie NetBeans utworzy wszystkie nowe pliki w kodowaniu UTF-8.

NetBeans domyślnie koduje UTF-8 krok po kroku

  • Przejdź do folderu etc w katalogu instalacyjnym NetBeans

  • Edytuj plik netbeans.conf

  • Znajdź wiersz netbeans_default_options

  • Dodaj -J-Dfile.encoding = UTF-8 w cudzysłowie wewnątrz tego wiersza

    (przykład netbeans_default_options="-J-Dfile.encoding=UTF-8":)

  • Uruchom ponownie NetBeans

Ustawiłeś domyślne kodowanie NetBeans UTF-8.

Twoje opcje netbeans_default_options mogą zawierać dodatkowe parametry w cudzysłowie. W takim przypadku dodaj -J-Dfile.encoding = UTF-8 na końcu ciągu. Oddziel go spacją od innych parametrów.

Przykład:

netbeans_default_options = "- J-klient -J-Xss128m -J-Xms256m -J-XX: PermSize = 32m -J-Dapple.laf.useScreenMenuBar = true -J-Dapple.awt.graphics UseQuartz = true -J-Dsun. java2d.noddraw = true -J-Dsun.java2d.dpiaware = true -J-Dsun.zip.disableMemoryMapping = true -J-Dfile.encoding = UTF-8 "

tutaj jest link do dalszych szczegółów


0

To rozwiązało mój problem

    String inputText = "some text with escaped chars"
    InputStream is = new ByteArrayInputStream(inputText.getBytes("UTF-8"));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.