用于解析数据的设计模式,数据会以两种不同方式分组并翻转
我正在寻找一个容易维护和扩展的设计模型,用于将一个Excel工作簿解析成两个独立的工作簿。这个过程需要从其他地方获取数据,比如命令行和数据库。大致情况如下。
我需要解析一个Excel工作簿,这个工作簿里有一个表格列出了独特的问题名称。可以从问题名称中可靠地解析出的唯一信息是书籍代码,这个代码用来识别与问题相关的教科书的标题和版本。问题名称的其他部分没有标准化,计算机无法可靠解析。问题名称的一般形式可以用以下的正则表达式来描述。
'^(\w+)\s(\w{1,2})\.(\w{1,2})\.(\w{1,3})\.(\w{1,3}\.)*$'
第一个子模式是书籍代码,第二个子模式通常是章节,其他的子模式可能是节、题型、题号或问题类型的信息。没有简单的逻辑,至少我找不到。
这个电子表格至少会有三列;一列是与问题相关的章节,第二列是与章节相关的节,第三列是某种资产,通过统一资源定位符(URL)来表示。
- 1 | 1 | qname1 | url | description | url | description ...
- 1 | 1 | qname2 | url | description
- 1 | 1 | qname3 | url | description | url | description | url |
资产可以通过完整或部分的URL来表示,部分URL需要在输入到应用程序之前完成。理论上,资产列的数量没有限制,资产会按类型分组在列中。有时还需要从数据库中获取额外的数据,或者与书籍代码结合,才能完成资产的URL,使其能够被使用资产的应用程序理解。
类型是一个抽象概念,目前有八种类型,每种类型在处理和完成URL时都有自己的逻辑,我每三到四个月就需要添加一种新类型及其逻辑。
对于每个资产的URL,可能会有一个描述列,用于在应用程序中显示的字符字符串,但并不总是有。(我已经解决了验证描述文本的问题,并将微软的一些模糊代码页压缩到7位ASCII可以处理的内容。)
现在所有细节都填好了,我可以开始解决实际的问题:解析文件。我需要将这个Excel工作簿中的信息分成两个独立的工作簿。第一个工作簿将按节将所有问题分组在行中。第一列是节的双重标识,后面的单元格是问题名称。
- 1.1 | qname1 | qname2 | qname3 | qname4 |
- 1.2 | qname1 | qname2 | qname3 |
- 1.3 | qname1 | qname2 | qname3 | qname4 | qname5
如上例所示,每个节的问题数量没有固定的限制。
第二个工作簿更复杂,每个资产占一行,问题名称如果有多个资产会重复。这个表格将有四到五列。第一列是资产的问题名称,第二列是用于选择资产在应用程序中正确图标的媒体类型,第三列是表示资产类型的字符串,第四列是资产的完整URL,第五列是资产的可选文本描述。
- q1 | mtype1 | atype1 | url | description
- q1 | mtype2 | atype2 | url | description
- q1 | mtype2 | atype3 | url | description
- q2 | mtype1 | atype1 | url | description
- q2 | mtype2 | atype3 | url | description
对于最初的六种类型,我确实有一个脚本可以将源Excel工作簿解析成另外两个Excel工作簿,我还能够添加两种类型,直到在实现第九和第十种类型时遇到困难。
导致我的脚本出错的原因是第九种类型实际上是原始六种类型中的一种子类型,但逻辑完全不同,而我主要是过程式的脚本无法适应,导致需要重复很多代码。我在脚本中也遇到了很多bug,这次我会先写测试。
我对最终两个工作簿的格式感到困惑,这个脚本是粘合代码,开发团队在没有从赞助商那里获得完整规格的情况下就继续了项目。我和开发人员在同一家公司工作,但我在编辑部门,编辑部是项目的共同赞助商,我被期望去解决这些麻烦的细节(我在打字时都快气炸了)。
我尝试过工厂模式,也尝试过不同的对象模型,但每个生成的工作簿差异很大。当我找到一个适合生成一个工作簿的设计时,代码并不适用于生成另一个工作簿。我真的希望能得到一些关于如何将源工作簿解析成两个工作簿的可维护和可扩展设计的想法,尽可能实现代码重用,或者得到一些同情。
1 个回答
我不太确定我能否帮上忙,但至少我对你表示同情 :-)
你有没有试过使用策略模式? 如果还没试过,可以看看这个链接,里面还有一个简单的Python例子。如果你的类型只是处理URL的方式不同,你可以把不同的逻辑放到策略的子类里。最糟糕的情况是,有些子类之间可能会有重复的逻辑,但至少你应用的其他部分就不需要关心这些细节,添加新类型应该也很简单。不过,你甚至可以通过不同的参数来重用部分重复的逻辑……我在这里完全是在猜测,因为我不知道你具体的问题是什么。
希望这对你有帮助……