[英]Write 16 bits character to .xlsx file using Apache POI in Java
我在Apache POI中遇到了問題。 問題是,我嘗試將16位字符值(例如CJK Unified Ideographs Extension B)放到.xlsx文件中。 但是,單元格值在生成的.xlsx文件中成為問號(如????)。
任何人都知道如何使用.xlsx格式處理Apache POI中的16位字符值???
我的POI版本是3.14
代碼示例如下:
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Test");
XSSFRow row1 = sheet.createRow(0);
XSSFCell r1c1 = row1.createCell(0);
r1c1.setCellValue("𤆕𤆕𤆕"); // value of CJK Unified Ideographs Extension B
XSSFCell r1c2 = row1.createCell(1);
FileOutputStream fos =new FileOutputStream("D:/temp/test.xlsx");
workbook.write(fos);
fos.close();
謝謝!
問題存在。 但不是從0x0000
到0xFFFF
16位(2字節)Unicode字符。 它的字符在Unicode編碼中需要超過2個字節。 這些是在Java字符中作為Unicode code points
提到的字符 :“Unicode代碼點用於U + 0000和U + 10FFFF之間范圍內的字符值,Unicode代碼單元用於16位字符值,即UTF-16編碼的代碼單元。“ Java平台在char數組和String和StringBuffer類中使用UTF-16表示。 在此表示中,補充字符(代碼點大於U + FFFF的字符)表示為一對char值,第一個來自高代理范圍,(\\ uD800- \\ uDBFF),第二個來自低 - 代理范圍(\\ uDC00- \\ uDFFF)。
問題出在org.apache.xmlbeans.impl.store.Saver
。 這適用於private char[] _buf
。 但由於char
max值為0xFFFF
,因此從0x10000
到0x10FFFF
Unicode代碼點無法存儲在char
。 因此,將存儲為一對char值。
有一種方法
/**
* Test if a character is valid in xml character content. See
* http://www.w3.org/TR/REC-xml#NT-Char
*/
private boolean isBadChar ( char ch )
{
return ! (
(ch >= 0x20 && ch <= 0xD7FF ) ||
(ch >= 0xE000 && ch <= 0xFFFD) ||
(ch >= 0x10000 && ch <= 0x10FFFF) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD)
);
}
該代碼完全錯誤,因為它檢查char
是否在0x10000
和0x10FFFF
之間。 如上所述,這根本不可能。
此外,它排除了高代理范圍(\\ uD800- \\ uDBFF)和低代理范圍(\\ uDC00- \\ uDFFF)作為壞字符。 因此,將排除作為一對char值的代碼點表示。
因此問題是由org.apache.xmlbeans.impl.store.Saver
的錯誤引起的。
補丁:
目標:不排除高代理范圍(\\ uD800- \\ uDBFF)和低代理范圍(\\ uDC00- \\ uDFFF),作為壞字符。 因此,在XML
不會排除存儲為兩個16位chars
U + 10000以上的Unicode代碼點。
下載Saver.java 。 將private boolean isBadChar ( char ch )
更改為
/**
* Test if a character is valid in xml character content. See
* http://www.w3.org/TR/REC-xml#NT-Char
*/
private boolean isBadChar ( char ch )
{
return ! (
(ch >= 0x20 && ch <= 0xFFFD ) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD)
);
}
在static final class OptimizedForSpeedSaver
和static final class TextSaver
。
編譯Saver.java
。
在類路徑之外的某處存儲xmlbeans-2.6.0.jar
的備份。
使用新的Saver$TextSaver.class
替換Saver$TextSaver.class
Saver$OptimizedForSpeedSaver.class
和Saver$TextSaver.class
在xmlbeans-2.6.0.jar
- > /org/apache/xmlbeans/impl/store/
。
現在,U + 10000以上的Unicode代碼點將存儲在sharedStrings.xml
。
免責聲明:這未經過充分測試。 所以不要在生產中使用它。 這里僅顯示描述問題。 也許xmlbeans.apache.org
上的一些程序員會找到時間來正確解決org.apache.xmlbeans.impl.store.Saver
的問題。
更新現在有一個xmlbeans-2.6.2.jar可用。 這已包含補丁。
更新現在有一個xmlbeans-3.0.0.jar可用。 這也包含補丁。
它確實:
/**
* Test if a character is valid in xml character content. See
* http://www.w3.org/TR/REC-xml#NT-Char
*/
static boolean isBadChar ( char ch )
{
return ! (
Character.isHighSurrogate(ch) ||
Character.isLowSurrogate(ch) ||
(ch >= 0x20 && ch <= 0xD7FF ) ||
(ch >= 0xE000 && ch <= 0xFFFD) ||
(ch >= 0x10000 && ch <= 0x10FFFF) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD)
);
}
因此它檢查char ch
是HighSurrogate
還是LowSurrogate
,如果是,它不是一個壞char。 好。
但是它會檢查char ch
是否大於或等於0x10000
。 再說一次:這對於char
是不可能的! char
的最大值是0xFFFF
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.