เข้ารหัสสตริงเป็น UTF-8


190

ฉันมีสตริงที่มีอักขระ "ñ" และฉันมีปัญหากับมัน ฉันต้องเข้ารหัสสตริงนี้เป็นการเข้ารหัสแบบ UTF-8 ฉันลองด้วยวิธีนี้ แต่ไม่ได้ผล:

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

ฉันจะเข้ารหัสสตริงนั้นเป็น utf-8 ได้อย่างไร


2
ไม่ชัดเจนว่าคุณพยายามทำอะไร myString มีอักขระñอย่างถูกต้องหรือไม่และคุณมีปัญหาในการแปลงเป็นอาร์เรย์ไบต์ (ในกรณีนั้นดูคำตอบจาก Peter และ Amir) หรือ myString เสียหายหรือคุณพยายามแก้ไข (ในกรณีนั้นให้ดูคำตอบจาก Joachim และฉัน)?
Michael Borgwardt

ฉันต้องส่ง myString ไปยังเซิร์ฟเวอร์ที่มีการเข้ารหัส utf-8 และฉันจำเป็นต้องแปลงอักขระ "ñ" เป็นการเข้ารหัส utf-8
อเล็กซ์

1
ทีนี้ถ้าเซิร์ฟเวอร์นั้นคาดว่า UTF-8 สิ่งที่คุณต้องส่งคือไบต์ไม่ใช่ String ดังนั้นตามคำตอบของ Peter ให้ระบุการเข้ารหัสในบรรทัดแรกและวางบรรทัดที่สอง
Michael Borgwardt

@Michael: ฉันยอมรับว่ามันไม่ชัดเจนว่าเจตนาที่แท้จริงคืออะไรที่นี่ ดูเหมือนจะมีคำถามมากมายที่ผู้คนพยายามแปลงที่ชัดเจนระหว่างสตริงและไบต์แทนที่จะปล่อยให้{In,Out}putStream{Read,Writ}ersทำสำหรับพวกเขา ฉันสงสัยว่าทำไม?
tchrist

1
@Michael: ขอบคุณฉันคิดว่าเหมาะสม แต่มันก็ทำให้ยากขึ้นกว่าที่มันเป็นใช่มั้ย ฉันไม่ค่อยชอบภาษาที่ใช้วิธีนี้และพยายามหลีกเลี่ยงการทำงานกับพวกเขา ฉันคิดว่ารูปแบบสตริงอักขระของ Java แทนที่จะเป็นไบต์ทำให้ทุกอย่างง่ายขึ้นมาก Perl และ Python ยังแชร์โมเดล“ ทุกอย่างคือ Unicode strings” ใช่ในทั้งสามคุณยังสามารถรับไบต์ถ้าคุณทำงาน แต่ในทางปฏิบัติดูเหมือนว่าหายากที่คุณต้องการจริง ๆ : นั่นค่อนข้างต่ำ รวมทั้งรู้สึกเหมือนแปรงแมวไปในทิศทางที่ผิดถ้าคุณรู้ว่าฉันหมายถึงอะไร :)
tchrist

คำตอบ:


140

String วัตถุใน Java ใช้การเข้ารหัส UTF-16 ที่ไม่สามารถแก้ไขได้

byte[]สิ่งเดียวที่สามารถมีการเข้ารหัสที่แตกต่างกันคือ ดังนั้นหากคุณต้องการ UTF-8 byte[]ข้อมูลแล้วคุณจำเป็นต้องมี หากคุณมีข้อมูลStringที่ไม่คาดคิดแสดงว่าปัญหาอยู่ที่สถานที่ก่อนหน้าซึ่งแปลงข้อมูลไบนารี่ไปเป็น a String(เช่นใช้การเข้ารหัสที่ไม่ถูกต้อง)


92
เทคนิคการพูดไบต์ [] ไม่มีการเข้ารหัสใด ๆ การเข้ารหัสไบต์อาร์เรย์ PLUS สามารถให้สตริงคุณได้
ปีเตอร์Štibraný

1
@ Peter: จริง แต่การเข้ารหัสการเข้ารหัสนั้นเหมาะสมbyte[]แต่ก็ไม่สมเหตุสมผลString(ยกเว้นการเข้ารหัสคือ UTF-16 ซึ่งในกรณีนี้เหมาะสมแล้ว แต่ยังไม่มีข้อมูลที่ไม่จำเป็น)
Joachim Sauer

4
String objects in Java use the UTF-16 encoding that can't be modified. คุณมีแหล่งข้อมูลอย่างเป็นทางการสำหรับคำพูดนี้หรือไม่?
Ahmad Hajjar

@AhmadHajjar docs.oracle.com/javase/10/docs/api/java/lang/… : "แพลตฟอร์ม Java ใช้การแทน UTF-16 ในอาร์เรย์ char และในคลาส String และ StringBuffer"
Maxi Gis

173

วิธีการเกี่ยวกับการใช้

ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(myString)

ดูการสนทนาของฉันกับปีเตอร์ แต่ถ้าสมมติฐานของเขาเกี่ยวกับคำถามนั้นถูกต้องทางออกของคุณก็ยังไม่เป็นที่คิดเพราะมันจะส่งคืน ByteBuffer
Michael Borgwardt

8
แต่ฉันจะรับสตริงที่เข้ารหัสได้อย่างไร มันจะส่งกลับ ByteBuffer
Alex

7
@Alex: ไม่สามารถมี Java String ที่เข้ารหัส UTF-8 ได้ คุณต้องการไบต์ดังนั้นใช้ ByteBuffer โดยตรง (อาจเป็นทางออกที่ดีที่สุดถ้าเป้าหมายของคุณคือส่งผ่านคอลเลกชันเครือข่าย) หรือ call array () เพื่อรับ byte []
Michael Borgwardt

2
สิ่งอื่นที่อาจมีประโยชน์คือการใช้ Charsets ของ Guava.UTF_8 enum แทนที่จะเป็น String ที่อาจใช้ UnsupportedEncodingException สตริง -> ไบต์: myString.getBytes(Charsets.UTF_8)และไบต์ -> new String(myByteArray, Charsets.UTF_8)String:
laughing_man

24
StandardCharsets.UTF_8ยิ่งไปกว่านั้นการใช้งาน พร้อมใช้งานใน Java 1.7+
Kat

81

ใน Java7 คุณสามารถใช้:

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

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

นี้มีประโยชน์มากกว่าว่ามันไม่ได้ประกาศgetBytes(String)throws UnsupportedEncodingException

หากคุณใช้ Java เวอร์ชันเก่าคุณสามารถประกาศค่าคงที่ชุดอักขระด้วยตนเองได้:

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
นี่คือคำตอบที่ถูกต้อง หากมีคนต้องการใช้ประเภทข้อมูลสตริงเขาสามารถใช้รูปแบบที่ถูกต้อง คำตอบที่เหลือจะถูกชี้ไปที่รูปแบบไบต์
Neeraj Shukla

ทำงานใน 6 ขอบคุณ
Itsik Mauyhas

คำตอบที่ถูกต้องสำหรับฉันเช่นกัน แต่สิ่งหนึ่งที่เมื่อฉันใช้เป็นตัวละครภาษาเยอรมันได้เปลี่ยนเป็น? ดังนั้นฉันใช้สิ่งนี้: byte [] ptext = myString.getBytes (UTF_8); ค่าสตริง = สตริงใหม่ (ptext, UTF_8); มันใช้งานได้ดี
Farhan Hafeez

3
ตัวอย่างโค้ดไม่สมเหตุสมผล หากคุณแปลงเป็น ISO-8859-1 เป็นครั้งแรกอาร์เรย์ของไบต์นั้นไม่ใช่ UTF-8 ดังนั้นบรรทัดถัดไปจึงไม่ถูกต้องทั้งหมด มันจะทำงานสำหรับสตริง ASCII แน่นอน String value = new String(myString);แต่แล้วคุณอาจรวมทั้งทำสำเนาง่าย:
Alexis Wilke

76

ใช้แทนbyte[] ptext = String.getBytes("UTF-8"); ใช้สิ่งที่เรียกว่า "การเข้ารหัสเริ่มต้น" ซึ่งอาจไม่ใช่ UTF-8getBytes()getBytes()


9
@Michael: เขาเห็นได้ชัดว่ามีปัญหาในการรับไบต์จากสตริง getBytes (การเข้ารหัส) หายไปอย่างไร ฉันคิดว่าบรรทัดที่สองอยู่ที่นั่นเพียงเพื่อตรวจสอบว่าเขาสามารถแปลงกลับได้หรือไม่
ปีเตอร์ibrtibraný

1
ฉันตีความว่ามีสตริงที่เสียหายและพยายาม "แก้ไข" โดยการแปลงเป็นไบต์และย้อนกลับ (ความเข้าใจผิดทั่วไป) ไม่มีสิ่งบ่งชี้ที่แท้จริงว่าบรรทัดที่สองเพิ่งตรวจสอบผลลัพธ์
Michael Borgwardt

@Michael ไม่มีไม่มีมันเป็นเพียงการตีความของฉัน ของคุณแตกต่างกันเพียง
ปีเตอร์Štibraný

1
@Peter: ถูกต้องเราต้องการคำชี้แจงจาก Alex ว่าเขาหมายถึงอะไรจริงๆ ไม่สามารถยกเลิก downvote แม้ว่าจะไม่มีการแก้ไขคำตอบ ...
Michael Borgwardt

33

Java String มีการเข้ารหัสภายในเสมอใน UTF-16 - แต่คุณควรคิดแบบนี้: การเข้ารหัสเป็นวิธีหนึ่งในการแปลระหว่างสตริงและไบต์

ดังนั้นหากคุณมีปัญหาการเข้ารหัสตามเวลาที่คุณมีสตริงมันสายเกินไปที่จะแก้ไข คุณต้องแก้ไขสถานที่ที่คุณสร้างสตริงนั้นจากไฟล์ฐานข้อมูลหรือการเชื่อมต่อเครือข่าย


1
เป็นความผิดพลาดทั่วไปที่เชื่อได้ว่าสายอักขระถูกเข้ารหัสภายในเป็น UTF-16 โดยปกติแล้วจะเป็น แต่ถ้าเป็นเพียงรายละเอียดการใช้งานเฉพาะของคลาส String เนื่องจากหน่วยเก็บข้อมูลภายในของข้อมูลตัวละครไม่สามารถเข้าถึงได้ผ่าน API สาธารณะการใช้งาน String ที่เฉพาะเจาะจงอาจตัดสินใจใช้การเข้ารหัสอื่น ๆ
jarnbjo

4
@jarnbjo: API ระบุอย่างชัดเจนว่า "สตริงแสดงถึงสตริงในรูปแบบ UTF-16" การใช้สิ่งอื่นเป็นรูปแบบภายในจะไม่มีประสิทธิภาพสูงและการใช้งานจริงทั้งหมดที่ฉันรู้จะใช้ UTF-16 ภายใน ดังนั้นหากคุณไม่สามารถอ้างได้ว่าคุณทำเช่นนั้น
Michael Borgwardt

มันไร้สาระที่จะแยกแยะระหว่างการเข้าถึงสาธารณะและการแสดงโครงสร้างข้อมูลภายในหรือไม่?
jarnbjo

6
JVM (เท่าที่เกี่ยวข้องกับ VM เลย) ใช้ UTF-8 สำหรับการเข้ารหัสสตริงเช่นในไฟล์คลาส การใช้งานของ java.lang.String ถูกแยกออกจาก JVM และฉันสามารถใช้คลาสสำหรับคุณโดยใช้การเข้ารหัสอื่น ๆ สำหรับการเป็นตัวแทนภายในหากจำเป็นจริงๆสำหรับคุณที่จะตระหนักว่าคำตอบของคุณไม่ถูกต้อง การใช้ UTF-16 เป็นรูปแบบภายในนั้นโดยส่วนใหญ่แล้วจะไม่มีประสิทธิภาพสูงเช่นกันเมื่อพูดถึงการใช้หน่วยความจำและฉันไม่เห็นว่าทำไมการใช้งาน Java สำหรับฮาร์ดแวร์ฝังตัวจะไม่ทำให้หน่วยความจำดีขึ้นแทนประสิทธิภาพ
jarnbjo

1
@jarnbjo: และอีกครั้ง: ตราบใดที่คุณไม่สามารถให้ตัวอย่างที่เป็นรูปธรรมของ JVM ที่มีมาตรฐานการดำเนินงาน API ไม่ภายในใช้สิ่งอื่นที่ไม่ใช่ UTF-16 จะใช้สายคำสั่งของฉันถูกต้อง และไม่คลาส String ไม่แยกจาก JVM จริง ๆ เนื่องจากสิ่งต่างๆเช่น intern () และพูลคงที่
Michael Borgwardt

22

คุณสามารถลองด้วยวิธีนี้

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

1
ฉันกำลังจะบ้า ขอขอบคุณที่ได้รับไบต์ใน "ISO-8859-1" ก่อนเป็นทางออก
Gian Gomen

2
นี่เป็นสิ่งที่ผิด หากสตริงของคุณมีอักขระ Unicode การแปลงเป็น 8859-1 จะทำให้เกิดข้อยกเว้นหรือแย่กว่านั้นให้สตริงที่ไม่ถูกต้อง (อาจเป็นสตริงที่ไม่มีอักขระที่มีรหัสจุด 0x100 ขึ้นไป)
Alexis Wilke

12

ในช่วงเวลาหนึ่งที่ฉันประสบปัญหานี้และสามารถแก้ไขได้ด้วยวิธีต่อไปนี้

ก่อนอื่นฉันต้องนำเข้า

import java.nio.charset.Charset;

จากนั้นฉันต้องประกาศค่าคงที่ที่จะใช้UTF-8และISO-8859-1

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

จากนั้นฉันสามารถใช้วิธีต่อไปนี้:

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
โซลูชั่นที่สมบูรณ์แบบ
Tunde Pizzle

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

และหากคุณต้องการอ่านจากไฟล์ข้อความที่เข้ารหัส "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

ฉันใช้โค้ดด้านล่างเพื่อเข้ารหัสอักขระพิเศษโดยระบุรูปแบบการเข้ารหัส

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

คู่มือแบบทีละขั้นตอนอย่างรวดเร็ววิธีกำหนดค่าการเข้ารหัสเริ่มต้น NetBeans UTF-8 ผลลัพธ์ NetBeans จะสร้างไฟล์ใหม่ทั้งหมดในการเข้ารหัส UTF-8

NetBeans การเข้ารหัสค่าเริ่มต้น UTF-8 คู่มือแบบทีละขั้นตอน

  • ไปที่โฟลเดอร์ etc ในไดเร็กทอรีการติดตั้ง NetBeans

  • แก้ไขไฟล์ netbeans.conf

  • ค้นหาบรรทัด netbeans_default_options

  • เพิ่ม -J-Dfile.encoding = UTF-8 ภายในเครื่องหมายคำพูดภายในบรรทัดนั้น

    (ตัวอย่าง: netbeans_default_options="-J-Dfile.encoding=UTF-8")

  • รีสตาร์ท NetBeans

คุณตั้งค่าการเข้ารหัสเริ่มต้น NetBeans UTF-8

netbeans_default_options ของคุณอาจมีพารามิเตอร์เพิ่มเติมภายในเครื่องหมายคำพูด ในกรณีเช่นนี้ให้เพิ่ม -J-Dfile.encoding = UTF-8 ที่ส่วนท้ายของสตริง คั่นด้วยช่องว่างจากพารามิเตอร์อื่น ๆ

ตัวอย่าง:

netbeans_default_options = "- J-client -J-Xss128m -J-Xms256m -J-XX: PermSize = 32m -J-Dapple.laf.useScreenMenuBar = จริง -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 "

นี่คือลิงค์สำหรับรายละเอียดเพิ่มเติม


0

นี่เป็นการแก้ไขปัญหาของฉัน

    String inputText = "some text with escaped chars"
    InputStream is = new ByteArrayInputStream(inputText.getBytes("UTF-8"));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.