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();
            }
  • 相关阅读:
    天下第一 (spfa判断环)
    网络的可靠性 (最小生成树)
    星际之门(一) (快幂+最小生成树)
    吝啬的国度 建图+深搜
    表达式求值 第九届河南省省赛
    Apple Tree (树形结构变为线性结构+树状数组)
    士兵杀敌(五)(线段树??)
    动物统计加强版
    Supermarket
    生活的烦恼
  • 原文地址:https://www.cnblogs.com/lixiaobin/p/OOXMLUnicode.html
Copyright © 2011-2022 走看看