最近做了一个关于导入Excel数据的简单工具,设计思路如下:
1.使用XML描述配置关系
2.引入简单表达式/函数对数据进行转换,处理
对EXCEL的转换配置定义如下:
<transform id="ts1" source="s1" target="t1">
<columns>
<column name="ID" dataType="int" type="autoint"/>
<column name="SITECODE" source="#Replace([$.2,$.1,$.3],[c1],[SiteName,RiverName],[SiteCode])" dataType="String"/>
<column name="SITECODE2" source="#Replace([$.2,c1,SiteCode)" dataType="String"/>
<column name="SITENAME" source="$.断面名称" dataType="String"/>
<column name="SAMPLINGTIME" source="#DateTime([$.采样日期],[yyyy-MM-01])" dataType="String"/>
<column name="SAMPLINGTIME2" source="#DateTime($.采样日期,yyyy-MM-01)" dataType="String"/>
<column name="SAMPLINGTIMESTR" source="#Date($.采样日期,[yyyy年MM月dd日])" dataType="String"/>
<column name="W_TEMP" source="$.4"/>
<column name="PH" source="$.5"/>
<column name="DO1" source="$.6"/>
<column name="CODcr" source="$.7"/>
<column name="NH4_N" source="$.8"/>
<column name="CODMN" source="$.9"/>
<column name="WaterGrade" source="#REPLACE([$.10],[c2],[name],[code])"/>
<column name="WaterGrade2" source="#REPLACE($.10,c2,name,code)"/>
<column name="WaterQuality" source="$.10"/>
<column name="TBR" source="#GET([s4,s5],[0],[1])"/>
<column name="SHR" source="#GET([s4,[3])"/>
<column name="YWZGFZR" source="#GET([s4,[6])"/>
<column name="TBRQ1" source="#SUBSTRING([#GET([s4,[3,4],5)],[5])"/>
<column name="TBRQ2" source="#SUBSTRING(#GET([s4,3,5),5)"/>
<column name="TBRQ3" source="#SUBSTRING(#GET([s4,[1-3],simsun;color:#002060;"> <column name="TBRQ" source="#DATETIME(#.TBRQ3,yyyy-MM-dd)"/>
<column name="REMARK" source="IMPORT"/>
<column name="ADDTIME" source="%NOW%"/>
<column name="UPDATETIME" source="%NOW%"/>
</columns>
</transform>
其中,source中的各种#,$,还有%等的字符串,为自定义的处理函数/表达式/常量,为了简单,现阶段函数表达式调用,只支持嵌套一层,上面代码中的(#SUBSTRING(#GET...)
定义的优先级规则为: 函数->表达式->常量
source的内容解析, 起初使用基于字符串匹配的方式, 勉强凑合工作, 但是马上就遇到了问题:
源: #Replace([$.2,[SiteCode])
解析目标: ReplaceFunctionExpression
Arguments[0]-> ExpressionCollection[3]->DataItemExpression
Arguments[1]-> c1 : StringExpression
Arguments[2]-> ExpressionCollection[2]->StringExpression
Arguments[3]-> SiteCode : StringExpression
如上:函数的参数之间是用逗号隔开的,但是参数有可能是另一个表达式,或者一个数组[,],这样子,使用切分字符串的方式来解析函数的参数(尤其是参数为其他函数/表达式)就有问题了
记得数据结构中有中缀表达式和后缀表达式解析的算法,应该是可以实现本例的要求,但是时间有限,也不需要一个很强大的功能,所以还是没有采用,最后的解决方案,还是采用正则表达式来解析.
最终构造的正则表达式为:
@"\[?\#(?<fn>\w+)\((?<fp>(.*?)+)\)\]?|\[(?<fp2>([-\$\.\#%\w]+,)*[-\$\.\#%\w]+)\]|\[?(?<fp3>[-\$\.\#%\w]+)\]?"
测试的样例字符串:
//#GET([s4,[5],[#GET2([s6,s7],8,9)],[100],110,[$.1,s31,s41,s51,你好],weixq,[$.中国,$H.5,#.99],$.22,#DateTime([$.采样日期],[yyyy-MM-01]),[yyyy-MM-01]
输出的匹配结果:
Result:12
1.Success:[True],Index:[0],Length:[17],Value:[#GET([s4,5)].
2.Success:[True],Index:[18],Length:[3],Value:[[5]].
3.Success:[True],Index:[22],Length:[20],Value:[[#GET2([s6,9)]].
4.Success:[True],Index:[43],Length:[5],Value:[[100]].
5.Success:[True],Index:[49],Value:[110].
6.Success:[True],Index:[53],Value:[[$.1,你好]].
7.Success:[True],Index:[74],Value:[weixq].
8.Success:[True],Index:[80],Length:[16],Value:[[$.中国,#.99]].
9.Success:[True],Index:[97],Length:[4],Value:[$.22].
10.Success:[True],Index:[102],Length:[33],Value:[#DateTime([$.采样日期],[yyyy-MM-01])].
11.Success:[True],Index:[137],Length:[12],Value:[[yyyy-MM-01]].
12.Success:[True],Index:[150],Value:[[ND,%ND,%ND%,ND%]].
其中解析的结果做为下一轮函数/表达式的输入,继续解析,直到不能在分解.
希望能给解析自定义字符串的朋友们一点启发:)