使用 C# 使用 Open XML 2.0 解析大型 Excel 文件。我遇到的问题是我正在解析的单元格没有数据类型,然后我检查 NumberFormatId 以确定它是小数、数字还是日期。我正在寻找数字/小数与日期的确切 NumberFormatId 范围。它们似乎无处不在,一些数字/小数的格式为 189,212,214,305,日期的值为 185、194、278 等。有人知道规范是否定义了这些范围吗?
已编辑 - 更多信息
下面是 xl 文件夹中 style.xml 文件中 194 的数字格式示例。
Excel 工作表来自世界不同地区,所以我认为数字格式不同,但它们是否重叠? numFmtId 194 会是不同文化设置中的日期以外的其他内容吗?
下面是我如何将“40574”之类的 c.CellValues 转换为日期,但问题是我如何知道“40574”是日期而不是数字?
DateTime.FromOADate(Convert.ToDouble(c.CellValue.Text));
目前,我通过检查是否没有 DataType 而不是检查 CellFormat 来执行此操作,但是当某些 NumberFormatId 不在我的检查中时会出现问题。
private Object FormatCellValue(Cell c, SharedStringTable ssTable, CellFormats cellFormats)
{
if (c.CellValue != null)
{
// If there is no data type, this must be a string that has been formatted as a number
if (c.DataType == null)
{
CellFormat cf;
if (c.StyleIndex == null)
{
cf = cellFormats.Descendants<CellFormat>().ElementAt<CellFormat>(0);
}
else
{
cf = cellFormats.Descendants<CellFormat>().ElementAt<CellFormat>(Convert.ToInt32(c.StyleIndex.Value));
}
if ((cf.NumberFormatId >= 14 && cf.NumberFormatId <= 22) ||
(cf.NumberFormatId >= 165 && cf.NumberFormatId <= 180) ||
cf.NumberFormatId == 278 || cf.NumberFormatId == 185 || cf.NumberFormatId == 196 ||
cf.NumberFormatId == 217 || cf.NumberFormatId == 326) // Dates
{
try
{
DateTime dt;
dt = DateTime.FromOADate(Convert.ToDouble(c.CellValue.Text));
...CODE CONTINUES
编辑
在我更新的帖子中,我忘记发布我在 style.xml 文件中找到的值:
<numFmt numFmtId="323" formatCode="mmm/yy;@"/>
因此我的问题是如何获取 formatCode 并解析它以确定它是否是一个日期?
下面是数字格式 323 的即时调试窗口的输出
{DocumentFormat.OpenXml.Spreadsheet.CellFormat}
base {DocumentFormat.OpenXml.OpenXmlCompositeElement}: {DocumentFormat.OpenXml.Spreadsheet.CellFormat}
Alignment: {DocumentFormat.OpenXml.Spreadsheet.Alignment}
ApplyAlignment: "1"
ApplyBorder: "1"
ApplyFill: "1"
ApplyFont: "1"
ApplyNumberFormat: "1"
ApplyProtection: "1"
BorderId: "64"
ExtensionList: null
FillId: "0"
FontId: "83"
FormatId: "37992"
LocalName: "xf"
NumberFormatId: "323"
PivotButton: null
Protection: {DocumentFormat.OpenXml.Spreadsheet.Protection}
QuotePrefix: "1"
最佳答案
格式 ID 值列表
下面是格式选项列表(source)
ID Format Code
0 General
1 0
2 0.00
3 #,##0
4 #,##0.00
9 0%
10 0.00%
11 0.00E+00
12 # ?/?
13 # ??/??
14 d/m/yyyy
15 d-mmm-yy
16 d-mmm
17 mmm-yy
18 h:mm tt
19 h:mm:ss tt
20 H:mm
21 H:mm:ss
22 m/d/yyyy H:mm
37 #,##0 ;(#,##0)
38 #,##0 ;[Red](#,##0)
39 #,##0.00;(#,##0.00)
40 #,##0.00;[Red](#,##0.00)
45 mm:ss
46 [h]:mm:ss
47 mmss.0
48 ##0.0E+0
49 @
但是,这些列表只指定了几种格式。根据这篇文章:Reading dates from OpenXml Excel files , ID 值小于 164 的格式是内置的。您还可以在那里找到更长的格式列表。
检查 xlsx 文件中的格式 ID 值
对于具有更大 ID 值的格式,您可以在文件本身中找到它们的定义。为了看到它们,您应该使用 zip 存档浏览器打开它并在 xl 中找到 styles.xml 文件> 目录。或者用 Open XML SDK 2.0 Productivity Tools 打开这个 xlsx 文件并导航到该文件的 /xl/styles.xml/x:StyleSheet 节点。
在该部分中,您应该能够看到文档中定义的格式以及分配给它们的 ID 值。带有格式的部分应该类似于这样:
...
<x:numFmts count="1">
<x:numFmt numFmtId="166" formatCode="yy/mm/dd;@" />
</x:numFmts>
...
查看此处保存的格式,似乎 id vlaues 可以特定于 xlsx 文件,因此可能相同的 ID 值可用于在两个不同的 xlsx 文件中定义不同的格式。但是,对于内置格式,它们是预定义的,因此在所有文件中都应该相同。
如果您在查找文件中的这种格式或其他信息方面需要任何帮助,请告诉我。
编辑
您还可以在本文档中找到有关数字格式的更多信息:http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx .
编辑二
您可以使用此代码获取包含 xlsx 文件中定义的所有格式的字典:
private Dictionary<uint, String> BuildFormatMappingsFromXlsx(String fileName)
{
Dictionary<uint, String> formatMappings = new Dictionary<uint, String>();
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
{
var stylePart = document.WorkbookPart.WorkbookStylesPart;
var numFormatsParentNodes = stylePart.Stylesheet.ChildElements.OfType<NumberingFormats>();
foreach (var numFormatParentNode in numFormatsParentNodes)
{
var formatNodes = numFormatParentNode.ChildElements.OfType<NumberingFormat>();
foreach (var formatNode in formatNodes)
{
formatMappings.Add(formatNode.NumberFormatId.Value, formatNode.FormatCode);
}
}
}
return formatMappings;
}
如果您想检查其中是否有日期,我想一个简单的方法是验证格式代码(由我发布的方法创建的字典中的值)是否包含 mm 和 yy 子串。
关于C# Open XML 2.0 NumberFormatId 范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11781210/
请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时
我正在尝试使用在我的代码中是动态的Time.local来安排时间。在每个月的第一天,我传递的值是Time.local(2009,9,-1,0)。在PHP中,这会将时间设置为上个月的最后一天。在ruby中,我只是得到“ArgumentError:参数超出范围”。是我用错了方法还是什么?谢谢。 最佳答案 您应该使用DateTime类而不是Time。(您可能需要先require'date'并安装activesupportgem。)它比Time更通用,并且可以用DateTime.civil(2009,9-1,-1,0)做你想做的事。为天
我想检查my_number是否在某个范围内,包括较高的值。在IF语句中我会简单地使用“x>100&&x但是我应该在Ruby案例中做什么(开关)?使用:casemy_numberwhenmy_number不起作用。备注:标准范围不包括my_number恰好为500的情况,并且我不想添加第二个“when”,因为我必须编写双重内容casemy_number#between100and500when100..500puts"Correct,dosomething"when500puts"Correct,dosomethingagain"end 最佳答案
我有一个变量,想从该变量中获取一定范围的位。我想要最干净的方式来做到这一点。如果x=19767并且我想要bit3-bit8(从右边开始):100110100110111在二进制中是19767。我想要括号100110(100110)111中的部分,所以答案是38。用Ruby实现以下功能的最简单/最干净/最优雅的方法是什么?bit_range(orig_num,first_bit,last_bit)附言。计算强度较低的答案可加分。 最佳答案 19767.to_s(2)[-9..-4].to_i(2)或19767>>3&0x3f更新:从头
是否有可能以某种方式访问Class.new范围内的a?a=5Class.new{defb;aend}.new.b#NameError:undefinedlocalvariableormethod`a'for#:0x007fa8b15e9af0>#:in`b' 最佳答案 即使@MarekLipka的回答是正确的——改变变量范围总是有风险的。这是可行的,因为每个block都带有创建它的上下文,因此您的局部变量a突然变得不那么局部了——它变成了一个“隐藏的”全局变量:a=5object=Class.new{define_method(
在Ruby类定义中,private关键字在以下场景中的作用域是什么:classFoodefbar_publicputs"public"endprivatedefbar_privateputs"private"enddefbar_public_2puts"anotherpublic"endendprivate是否只作用于bar_private?还是在bar_public_2上? 最佳答案 在您的例子中,bar_private和bar_public_2都是私有(private)的。那是因为这两种方法都在private关键字的“范围内”。