[英]How to convert an originally Latin-1 char[] from SAX parser to a proper UTF-8 String?
我一直在嘗試使用Java SAX解析器來解析ISO-8859-1字符編碼中的XML文件。 這不是很好,但是ä和ö這樣的特殊角色給我帶來了麻煩。 簡而言之, ContentHandler.characters(...)方法給了我奇怪的字符,你甚至不能使用char數組來構造具有指定編碼的String。
這是兩個文件中的完整最小工作示例:
latin1.xml:
<?xml version='1.0' encoding='ISO-8859-1' standalone='no' ?>
<x>Motörhead</x>
該文件以所述Latin-1格式保存,因此hexdump給出了:
$ hexdump -C latin1.xml
00000000 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 27 31 |<?xml version='1|
00000010 2e 30 27 20 65 6e 63 6f 64 69 6e 67 3d 27 49 53 |.0' encoding='IS|
00000020 4f 2d 38 38 35 39 2d 31 27 20 73 74 61 6e 64 61 |O-8859-1' standa|
00000030 6c 6f 6e 65 3d 27 6e 6f 27 20 3f 3e 0a 3c 78 3e |lone='no' ?>.<x>|
00000040 4d 6f 74 f6 72 68 65 61 64 3c 2f 78 3e |Mot.rhead</x>|
所以“ö”用單個字節f6編碼,正如你所期望的那樣。
然后,這是以UTF-8格式保存的Java文件:
MySAXHandler.java:
import java.io.File;
import java.io.FileReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class MySAXHandler extends DefaultHandler {
private static final String FILE = "latin1.xml"; // Edit this to point to the correct file
@Override
public void characters(char[] ch, int start, int length) {
char[] dstCharArray = new char[length];
System.arraycopy(ch, start, dstCharArray, 0, length);
String strValue = new String(dstCharArray);
System.out.println("Read: '"+strValue+"'");
assert("Motörhead".equals(strValue));
}
private XMLReader getXMLReader() {
try {
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setContentHandler(new MySAXHandler());
return xmlReader;
} catch (Exception ex) {
throw new RuntimeException("Epic fail.", ex);
}
}
public void go() {
try {
XMLReader reader = getXMLReader();
reader.parse(new InputSource(new FileReader(new File(FILE))));
} catch (Exception ex) {
throw new RuntimeException("The most epic fail.", ex);
}
}
public static void main(String[] args) {
MySAXHandler tester = new MySAXHandler();
tester.go();
}
}
運行該程序的結果是輸出Read: 'Mot rhead'
(ö替換為“?in a box”)然后由於斷言錯誤而崩潰。 如果查看char數組,您將看到編碼字母char的char由三個字節組成。 它們對我沒有任何意義,因為在UTF-8中,應該用兩個字節編碼。
我試過了什么
我已經嘗試將字符數組轉換為字符串,然后將該字符串的字節傳遞給另一個帶有charset編碼參數的字符串構造函數。 我也玩過CharBuffers並試圖找到可能與Locale類一起使用的東西來解決這個問題,但我嘗試的東西似乎都沒有用。
問題是你正在使用FileReader
來讀取文件,而不是像以前建議的評論者那樣使用FileInputStream。 在go
方法中,取出FileReader
並替換為FileInputStream
。
public void go() {
try {
XMLReader reader = getXMLReader();
reader.parse(new InputSource(new FileInputStream(new File(FILE))));
} catch (Exception ex) {
throw new RuntimeException("The most epic fail.", ex);
}
}
現在的方式, FileReader
使用默認的平台編碼來解碼字符,然后再將它們傳遞給SAX解析器,這不是你想要的。 如果用FileInputStream
替換,則XML解析器應該使用字符集編碼正確讀取處理指令,並為您處理字符集解碼。
因為FileReader正在進行解碼,所以您會看到無效字符。 如果你讓SAX解析器處理它,它應該會很好。
在characters()方法中:
構造一個新的String對象時,首先將char []轉換為byte [],然后調用構造函數'new String(byte [],String charSetName)',而不是默認的'new String(char [])'
如果您需要更多幫助,請嘗試: http : //www.exampledepot.com/egs/java.nio.charset/ConvertChar.html
你在渾水中釣魚; 很多事情都是誤導。 正如@JBNizet指出的那樣:Reader以某種編碼方式讀取文本,已經在讀取字節的InputStream上進行轉換。 如果您未指明編碼,則將采用平台編碼。
reader.parse(new InputSource(new FileInputStream(new File(FILE))));
這與XML中的實際編碼屬性無關。
java源代碼編碼必須與編輯器編碼一致,否則字符串文字會出錯。
System.out.println也可能被誤傳。
此外,“ISO-8859-1”是Windows Latin-1“Windows-1252”的子集。 如果您遇到特殊字符問題,建議使用“Windows-1252”(在java中可以使用“Cp1252”)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.