OOXML中回车等特殊字符处理方法
问题点: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中回车等特殊字符处理方法的更多相关文章
- mssql sqlserver 使用sql脚本剔除数据中的tab、空格、回车等特殊字符的方法分享
摘要: 在sqlserver开发中,常常有同事反馈无法剔除空格,我们可以通过仔细检查发现,并不是空格字符,而是tab键,如下所示: 解决方法: 对于这些特殊字符的替换,我们需采用字符所对应的ascii ...
- JavaScript中url 传递参数(特殊字符)解决方法及转码解码的介绍
有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.下表中列出了一些URL特殊符号及编码 十六进制值 1. + URL 中+号表示空格 %2B 2. 空 ...
- 在php中防止SQL注入的方法
摘要:我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最主要就是要配置php.ini中的内容,让我们执行 php能够更安全.整个PH ...
- 客户端向服务端传送特殊字符解决方法(检测到有潜在危险的 Request.Form 值)
当客户端向服务端传输特殊字符时报错,错误信息如下图:
- SQL对like 操作中的特殊字符处理方法
SQL对like 操作中的特殊字符处理方法: SQL Server查询过程中,单引号 ' 是特殊字符,所以在查询的时候要转换成双单引号 '' . 在like操作还有以下特殊字符:下划线_, ...
- Mybatis特殊字符处理,Mybatis中xml文件特殊字符的处理
Mybatis特殊字符处理,Mybatis中xml文件特殊字符的处理 >>>>>>>>>>>>>>>>& ...
- Python中防止sql注入的方法详解
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库.下面这篇文章主要给大家介绍了关于Python中 ...
- 转:Scanner中nextLine()方法和next()方法的区别
原文地址:https://blog.csdn.net/hello_word2/article/details/54895106 总结:next() 读取第一个 空白符之前(不包括空白符)的内容,nex ...
- Maya中输出nuke脚本的方法
因项目需要,三维部门跟踪组动画组都需要一个能够快速输出nuke预合成工程的脚本.脚本已经写完,源码不便于放出来,写一个大致思路吧. 我首先分析了nuke工程,内部包含了哪些节点,这些节点有哪些属性需要 ...
随机推荐
- 【IDEA】IDEA自动生成文档注释的设置方法
Digest:今天和大家分享一下如何使用IntelliJ IDEA快速生成文档注释 IntelliJ IDEA创建自定义文档注释模板 1.打开IntelliJ IDEA,依次点击 File --> ...
- (Java) byte[] 和 base64 字符串之间的转换
import org.apache.commons.codec.binary.Base64; public class UtilHelper { //base64字符串转byte[] public s ...
- 一款用于绘制状态机转换图和流程图的web在线绘图工具
大型软件系统中离不开各类状态机的处理,日常工作中也涉及到各类事务处理流程:从表现力看文不如表,表不如图:因此日常工作中经常需要绘制各种状态机的状态转换图和流程图,以协助理解代码逻辑和各类事务处理流程等 ...
- 编译原理实验 NFA子集法构造DFA,DFA的识别 c++11实现
实验内容 将非确定性有限状态自动机通过子集法构造确定性有限状态自动机. 实验步骤 1,读入NFA状态.注意最后需要设置终止状态. 2,初始态取空,构造DFA的l0状态,将l0加入未标记状态队列que ...
- 原生JS实现集合结构
1. 前言 集合是由一组无序且唯一(即不能重复)的项组成的.你可以把集合想象成一个既没有重复元素,也没有顺序概念的数组.在ES6中已经内置了集合这一数据结构--Set.接下来,我们就用原生JS来实现这 ...
- SSHD服务安全的连接
SSHD服务 SSH 安全的远程连接 OpenSSH 工具 centos服务端的包:openssh-server centos客户端的包:openssh-clients 主要配置文件一般安装完成后再/ ...
- xms跨平台基础框架 - 基于.netcore
背景 敝人经过多年开发,数百个项目“打磨(折磨)”,各种国内外框架平台都有涉及,没有一款称心顺手的,原因有三,一是设计反人类,二是不开源根本无法突破框架限制,三是即使开源也是阉割版,然后xms就开始萌 ...
- 微信小程序this.data和this.setData({})的区别
this.data.xx是用来获取页面data对象的----------只是js(逻辑层)数据的更改: this.setData是用来更新界面的---------用于更新view层的.
- 使用 Casbin 作为 ThinkPHP 的权限控制中间件
PHP-Casbin 是一个强大的.高效的开源访问控制框架,它支持基于各种访问控制模型的权限管理. Think-Casbin 是一个专为 ThinkPHP5.1 定制的 Casbin 的扩展包,使开发 ...
- Jumpserver v2.0.0 使用说明
官方文档:http://www.jumpserver.org/ — 登录脚本 — 1.1 使用paramiko原生ssh协议登录后端主机(原来版本使用pexpect模拟登录) 1.2 新增使用别名或备 ...