POI处理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(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因为使用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表里面需要处理的部分: 遍历所有字符,将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(); } 复制代码 每天成就一小步,积累下来就是一大步。 转发本文请注明出处,谢谢您的阅读与分享!https://www.cnblogs.com/lixiaobin/p/OOXMLUnicode.html