问题点: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. 【IDEA】IDEA自动生成文档注释的设置方法

    Digest:今天和大家分享一下如何使用IntelliJ IDEA快速生成文档注释 IntelliJ IDEA创建自定义文档注释模板 1.打开IntelliJ IDEA,依次点击 File --> ...

  2. (Java) byte[] 和 base64 字符串之间的转换

    import org.apache.commons.codec.binary.Base64; public class UtilHelper { //base64字符串转byte[] public s ...

  3. 一款用于绘制状态机转换图和流程图的web在线绘图工具

    大型软件系统中离不开各类状态机的处理,日常工作中也涉及到各类事务处理流程:从表现力看文不如表,表不如图:因此日常工作中经常需要绘制各种状态机的状态转换图和流程图,以协助理解代码逻辑和各类事务处理流程等 ...

  4. 编译原理实验 NFA子集法构造DFA,DFA的识别 c++11实现

    实验内容 将非确定性有限状态自动机通过子集法构造确定性有限状态自动机. 实验步骤 1,读入NFA状态.注意最后需要设置终止状态. 2,初始态取空,构造DFA的l0状态,将l0加入未标记状态队列que ...

  5. 原生JS实现集合结构

    1. 前言 集合是由一组无序且唯一(即不能重复)的项组成的.你可以把集合想象成一个既没有重复元素,也没有顺序概念的数组.在ES6中已经内置了集合这一数据结构--Set.接下来,我们就用原生JS来实现这 ...

  6. SSHD服务安全的连接

    SSHD服务 SSH 安全的远程连接 OpenSSH 工具 centos服务端的包:openssh-server centos客户端的包:openssh-clients 主要配置文件一般安装完成后再/ ...

  7. xms跨平台基础框架 - 基于.netcore

    背景 敝人经过多年开发,数百个项目“打磨(折磨)”,各种国内外框架平台都有涉及,没有一款称心顺手的,原因有三,一是设计反人类,二是不开源根本无法突破框架限制,三是即使开源也是阉割版,然后xms就开始萌 ...

  8. 微信小程序this.data和this.setData({})的区别

    this.data.xx是用来获取页面data对象的----------只是js(逻辑层)数据的更改: this.setData是用来更新界面的---------用于更新view层的.

  9. 使用 Casbin 作为 ThinkPHP 的权限控制中间件

    PHP-Casbin 是一个强大的.高效的开源访问控制框架,它支持基于各种访问控制模型的权限管理. Think-Casbin 是一个专为 ThinkPHP5.1 定制的 Casbin 的扩展包,使开发 ...

  10. Jumpserver v2.0.0 使用说明

    官方文档:http://www.jumpserver.org/ — 登录脚本 — 1.1 使用paramiko原生ssh协议登录后端主机(原来版本使用pexpect模拟登录) 1.2 新增使用别名或备 ...