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

实例:以下字符abc\rcde

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

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

代码如下:

            string path = @"C: \Users\Desktop\test.xlsx";

            var book = new XSSFWorkbook();
var sheet = book.CreateSheet("test");
var row = sheet.GetRow() ?? sheet.CreateRow();
var cell = row.GetCell() ?? row.CreateCell(); cell.SetCellValue("abc\rcde"); using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
{
book.Write(file);
file.Close();
}

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

原因

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 = ; 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表里面需要处理的部分:

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

字符转换为Unicode代码:

        private static string EncodeXmlUTF(string value)
{
var builder = new StringBuilder();
foreach (char c in value.ToCharArray())
{
if (c < )
{
builder.Append($"_x{(c < 16 ? "" : "")}{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(, , 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 = ;
for (int i = ; i < mc.Count;i++ )
{
int pos = mc[i].Index;
if (pos > idx)
{
buf.Append(value.Substring(idx, pos-idx));
} String code = mc[i].Groups[].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();
}

OOXML中回车等特殊字符处理方法的更多相关文章

  1. mssql sqlserver 使用sql脚本剔除数据中的tab、空格、回车等特殊字符的方法分享

    摘要: 在sqlserver开发中,常常有同事反馈无法剔除空格,我们可以通过仔细检查发现,并不是空格字符,而是tab键,如下所示: 解决方法: 对于这些特殊字符的替换,我们需采用字符所对应的ascii ...

  2. JavaScript中url 传递参数(特殊字符)解决方法及转码解码的介绍

    有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.下表中列出了一些URL特殊符号及编码   十六进制值 1. + URL 中+号表示空格 %2B 2. 空 ...

  3. 在php中防止SQL注入的方法

    摘要:我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最主要就是要配置php.ini中的内容,让我们执行 php能够更安全.整个PH ...

  4. 客户端向服务端传送特殊字符解决方法(检测到有潜在危险的 Request.Form 值)

    当客户端向服务端传输特殊字符时报错,错误信息如下图:

  5. SQL对like 操作中的特殊字符处理方法

    SQL对like 操作中的特殊字符处理方法:    SQL Server查询过程中,单引号 ' 是特殊字符,所以在查询的时候要转换成双单引号 '' .    在like操作还有以下特殊字符:下划线_, ...

  6. Mybatis特殊字符处理,Mybatis中xml文件特殊字符的处理

    Mybatis特殊字符处理,Mybatis中xml文件特殊字符的处理 >>>>>>>>>>>>>>>>& ...

  7. Python中防止sql注入的方法详解

    SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库.下面这篇文章主要给大家介绍了关于Python中 ...

  8. 转:Scanner中nextLine()方法和next()方法的区别

    原文地址:https://blog.csdn.net/hello_word2/article/details/54895106 总结:next() 读取第一个 空白符之前(不包括空白符)的内容,nex ...

  9. Maya中输出nuke脚本的方法

    因项目需要,三维部门跟踪组动画组都需要一个能够快速输出nuke预合成工程的脚本.脚本已经写完,源码不便于放出来,写一个大致思路吧. 我首先分析了nuke工程,内部包含了哪些节点,这些节点有哪些属性需要 ...

随机推荐

  1. 第二十九章 System V共享内存

    共享内存数据结构 共享内存函数 shmget int shmget(key_t key, size_t size, int shmflg); 功能: 用于创建共享内存 参数: key : 这个共享内存 ...

  2. Java 中文数字转换为阿拉伯数字

    贴出代码,方便学习交流,稍后放出镜像问题的代码 package com.thunisoft.cail.utils; import com.sun.istack.internal.NotNull; im ...

  3. 重邮二进制群-pwn1

    给学弟们练手的题目,做的过程中接触一些基本概念 #include <stdio.h> #include <unistd.h> int main() { ]; welcome() ...

  4. 「考试」 Or

    不得不说是一道多项式神题了. 虽然说颓代码颓的很厉害不过最终A掉了. 好好讲一讲这道题. 涉及的知识点是:高阶导数,NTT,指数型母函数,泰勒公式,以及意志力和数学推导能力. 那就开始了. 一个测试点 ...

  5. python爬虫-携程-eleven参数

    携程-eleven分析 一.eleven的位置 通过对旁边栈的分析,它是在另一个js文件中调用的.那个js文件是一个自调用的函数,所以我们可以直接copy下来,用浏览器执行看看 执行运行是会报错的,u ...

  6. PHP对象继承

    PHP对象继承<?php class foo{ public function printItem($string) { echo 'Foo: ' . $string . PHP_EOL; } ...

  7. Linux命令实战(三)

    1.file检查并显示文件类型(determine file type) 一般用法就是file 后面接要查看的文件 可以一个或多个 [root@test test]# ll total 140 -rw ...

  8. SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析

    在上一篇博客中分析了springBoot启动流程,大体的轮廓只是冰山一角.今天就来看一下springBoot的亮点功能:自动化装配功能. 先从@SpringBootApplication开始.在启动流 ...

  9. 破解微擎安装,免费搭建微擎,免费破解微擎,微擎破解版本,最新版本V2.1.2,一键安装!!

    ​ 微擎是一款基于WEB2.0(PHP+Mysql)技术架构,免费开源的公众平台管理系统,一款致力于将小程序和公众号商业化.智慧化.场景化的自助引擎.微擎提供公众号.微信小程序.支付宝小程序.百度熊掌 ...

  10. 关于RAID 10的介绍与创建

    一.RAID 10的简介 定义: RAID10也被称为镜象阵列条带.象RAID0一样,数据跨磁盘抽取:象RAID1一样,每个磁盘都有一个镜象磁盘, 所以RAID 10的另一种会说法是 RAID 0+1 ...