繁体   English   中英

使用Java中的Apache POI将16位字符写入.xlsx文件

[英]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();

谢谢!

问题存在。 但不是从0x00000xFFFF 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 ,因此从0x100000x10FFFF 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是否在0x100000x10FFFF之间。 如上所述,这根本不可能。

此外,它排除了高代理范围(\\ 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 OptimizedForSpeedSaverstatic final class TextSaver

编译Saver.java

在类路径之外的某处存储xmlbeans-2.6.0.jar的备份。

使用新的Saver$TextSaver.class替换Saver$TextSaver.class Saver$OptimizedForSpeedSaver.classSaver$TextSaver.classxmlbeans-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 chHighSurrogate还是LowSurrogate ,如果是,它不是一个坏char。 好。

但是它会检查char ch是否大于或等于0x10000 再说一次:这对于char是不可能的! char的最大值是0xFFFF

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM