zoukankan      html  css  js  c++  java
  • OOXML中回车等特殊字符处理方法

    问题点:NPOI处理xlsx文档时,将 写成了换行符。

    实例:以下字符abc cde

     如果直接复制到Excel 2016,显示结果如下(单元格设置为折行显示):

     如果用NPOI写入Xlsx文档,显示结果如下(单元格设置为折行显示):

     代码如下:

                string path = @"C: UsersDesktop	est.xlsx";
    
                var book = new XSSFWorkbook();
                var sheet = book.CreateSheet("test");
                var row = sheet.GetRow(1) ?? sheet.CreateRow(1);
                var cell = row.GetCell(1) ?? row.CreateCell(1);
    
                cell.SetCellValue("abc
    cde");
    
                using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
                {
                    book.Write(file);
                    file.Close();
                }

    查看生成的Excel内部数据确实成了换行符:

     

    原因

    OOXML因为使用XML格式存储数据,所以XML中无法表示的字符需要转换为Unicode码存储,Excel打开时会自动将这些Unicode码转换为原来的字符显示。由于NPOI需要兼容以前版本Excel,而没有处理' '  ' '  ' '这几个字符。

    NPOI源码:

            public static string ExcelEncodeString(string t)
            {
                StringWriter sw = new StringWriter();
                //poi dose not add prefix _x005f before _x????_ char.
                //if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)"))
                //{
                //    Match match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)");
                //    int indexAdd = 0;
                //    while (match.Success)
                //    {
                //        t = t.Insert(match.Index + indexAdd, "_x005F");
                //        indexAdd += 6;
                //        match = match.NextMatch();
                //    }
                //}
                for (int i = 0; i < t.Length; i++)
                {
                    if (t[i] <= 0x1f && t[i] != '	' && t[i] != '
    ' && t[i] != '
    ') //Not Tab, CR or LF
                    {
                        //[0x00-0x0a]-[
    	]
                        //poi replace those chars with ?
                        sw.Write('?');
                        //sw.Write("_x00{0}_", (t[i] < 0xa ? "0" : "") + ((int)t[i]).ToString("X"));
                    }
                    else if (t[i] == 'uFFFE')
                    {
                        sw.Write('?');
                    }
                    else
                    {
                        sw.Write(t[i]);
                    }
                }
                return sw.ToString();
            }

    对应方法

    Unicode表里面需要处理的部分:

    遍历所有字符,将001f内的字符都转换为Unicode。

    字符转换为Unicode代码:

            private static string EncodeXmlUTF(string value)
            {
                var builder = new StringBuilder();
                foreach (char c in value.ToCharArray())
                {
                    if (c < 32)
                    {
                        builder.Append($"_x{(c < 16 ? "000" : "00")}{Convert.ToInt32(c):X}_");
                    }
                    else
                    {
                        builder.Append(c);
                    }
                }
                return builder.ToString();
            }

    NPOI的场合

    读取端:由于NPOI已经做了转换处理,所有不需要特别的代码。

    写入端:

    cell.SetCellValue(EncodeXmlUTF(text));

    设置多文本的特殊处理:因为NPOI里面需要用到字符串位置信息,所有在它处理之后替换原先字符为Unicode。

                var text = new XSSFRichTextString("abcefg
    hijklmn");
                text.ApplyFont(commonFont.Index);
                text.ApplyFont(1, 10, green_font);
    
                foreach (var r in text.GetCTRst().r)
                {
                    r.t = EncodeXmlUTF(r.t);
                }

    OpenXML的场合

    需要在SharedStringTable中写入SharedStringItem:

    shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new Text(EncodeXmlUTF(value))));

    读取的时候同理需要将SharedStringItem.InnerText转码后的数据转换回来:

    Unicode转换回来代码:

            static String UtfDecode(String value)
            {
                if (value == null) return null;
    
                StringBuilder buf = new StringBuilder();
                MatchCollection mc = utfPtrn.Matches(value);
                int idx = 0;
                for (int i = 0; i < mc.Count;i++ )
                {
                        int pos = mc[i].Index;
                        if (pos > idx)
                        {
                            buf.Append(value.Substring(idx, pos-idx));
                        }
    
                        String code = mc[i].Groups[1].Value;
                        int icode = Int32.Parse(code, System.Globalization.NumberStyles.AllowHexSpecifier);
                        buf.Append((char)icode);
    
                        idx = mc[i].Index+mc[i].Length;
                    }
                buf.Append(value.Substring(idx));
                return buf.ToString();
            }
  • 相关阅读:
    UVa 1354 天平难题 (枚举二叉树)
    广西邀请赛总结
    UVa 12118 检查员的难题 (dfs判连通, 构造欧拉通路)
    UVA
    Uva 127 "Accordian" Patience (模拟)
    UVA 10539 Almost Prime Numbers( 素数因子)
    HDU 1272 小希的迷宫(并查集)
    HDU 1213 How Many Tables (并查集)
    POJ 2236 Wireless Network(并查集)
    HDU 1233 还是畅通工程 ( Kruskal或Prim)
  • 原文地址:https://www.cnblogs.com/lixiaobin/p/OOXMLUnicode.html
Copyright © 2011-2022 走看看