阿里云,腾讯云_OOXML中回车等特别字符处置惩罚要领

  • 阿里云,腾讯云_OOXML中回车等特别字符处置惩罚要领已关闭评论
  • 100 人浏览
  • A+
所属分类:首页

问题点:NPOI处置惩罚xlsx文档时,将\r写成了换行符。

实例:以下字符abc\rcde

阿里云,腾讯云_OOXML中回车等特别字符处置惩罚要领

 

 

 假如直接复制到Excel 2016,显现效果以下(单元格设置为折行显现):

阿里云,腾讯云_OOXML中回车等特别字符处置惩罚要领

 

 

 假如用NPOI写入Xlsx文档,显现效果以下(单元格设置为折行显现):

阿里云,腾讯云_OOXML中回车等特别字符处置惩罚要领

 

 

 代码以下:

            string path = @"C: \Users\Desktop\test.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\rcde");

            using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
            {
                book.Write(file);
                file.Close();
            }

检察生成的Excel内部数据确切成了换行符:

 阿里云,腾讯云_OOXML中回车等特别字符处置惩罚要领

缘由

OOXML因为运用XML花样存储数据,所以XML中没法示意的字符须要转换为Unicode码存储,Excel翻开时会自动将这些Unicode码转换为本来的字符显现。因为NPOI须要兼容之前版本Excel,而没有处置惩罚'\t'  '\n'  '\r'这几个字符。

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' && t[i] != '\n' && t[i] != '\r') //Not Tab, CR or LF
                {
                    //[0x00-0x0a]-[\r\n\t]
                    //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表内里须要处置惩罚的部份:

阿里云,腾讯云_OOXML中回车等特别字符处置惩罚要领

遍历一切字符,将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\rhijklmn");
            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();
        }

 

腾讯云双十一活动