簡體   English   中英

如何將原始的Latin-1 char []從SAX解析器轉換為正確的UTF-8字符串?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM