以下是对我的正则表达式解决方案的评论,激发了我进行分析。
“这不是一个用正则表达式有点过于丑陋的情况吗?我认为直接编写代码会更简单易懂。- C. Ross”
我的回答如下。
“也许吧。我选择使用正则表达式是因为你可以涵盖所有情况(如果你的正则表达式是正确的)。如果你使用String.Split()等方法来做,如果输入有效,则可以得到更简单的解决方案。但是使用字符串方法捕获所有无效输入可能真的会变成一场恐怖。当我开始将数字解析为十进制数时,我已经知道它是一个有效的数字,不会失败。或者想想像'1-2-3;,-1:.:'这样的输入 - 你会将它们拆分,但很可能在后面崩溃或返回一个无意义的结果。在David的代码中,访问part[2]将超出输入'1:2'的范围,解析可能会失败,而且还有几个未被捕获的错误。捕获它们所有可能会使代码比正则表达式代码更难读。- danbruc”
所以,我决定使用微软强大的工具
PEX分析我的正则表达式方法和David的字符串操作方法。我没有修改David的代码,而是用构建结果语句代替了我的解决方案中的控制台输出,这些语句与David一样生成
List<List<Decimal>>
。
为了使全面的分析成为可能,我限制PEX只生成长度小于45个字符的输入,并且仅使用以下9种不同的字符。
019.;,-:!
没有必要使用所有数字,因为它们应该都表现相同。我包括9是为了方便发现溢出,但0和1也足够了——PEX可能会找到1000而不是999。我包括0和1是为了发现非常小的数字(例如0.000[...]001)的错误,但没有出现任何问题。我认为非常小的数字被默默地四舍五入为零,但我没有进一步调查。或者44个字符(由于28到29位小数的精度加上其他字符的空间)只是生成足够小的数字的长度不够。其他字符包括在内,因为它们是输入中的其他有效字符。最后,我包括感叹号作为无效字符的替代。
分析结果证明了我的正确性。PEX在我的代码中发现了两个错误。我没有检查空输入(我有意跳过了这一部分,以便专注于重要部分),导致了众所周知的NullReferenceException,而PEX发现输入“999999999999999999999999999999”会导致Decimal.Parse()失败并出现OverflowException异常。
PEX还报告了一些错误的负面结果。例如,“!;9,;.0;990:!!:,900:09”被报告为导致FormatException的输入。重新运行生成的测试不会引发任何异常。事实证明,“.0”在探索期间导致测试失败。查看其他失败的测试显示,在探索期间以小数点开头的所有输入都会导致Decimal.Parse()失败。但它们是有效的数字,在正常执行期间不会失败。我无法解释这些错误的正面结果。
以下是对字符串操作解决方案运行一次PEX的结果。两个实现都缺少空值检查和溢出异常处理。但简单的字符串操作解决方案无法处理许多格式不正确的输入。它们几乎都导致FormatException异常,但PEX还发现了我预测到的IndexOutOfRangeException异常。
FormatException: "!,"
FormatException: ","
FormatException: "1,"
FormatException: "!"
FormatException: ";9"
FormatException: "::"
FormatException: "!.999009"
FormatException: "!.0!99!9"
FormatException: "0,9.90:!!,,,!,,,,,,!,,,0!!!9,!"
FormatException: ""
FormatException: "-99,9"
FormatException: "1,9,,,!,,,,,,9,,,9,1,!9,,,,!,!"
FormatException: "!:,"
FormatException: "!9!:.!!,!!!."
FormatException: "!:"
IndexOutOfRangeException: "1:9"
FormatException: "09..::!"
FormatException: "9,0..:!.!,,,!,,,,,,!,,,!!-,!,!"
OverflowException: "99999999999999999999999999999999999999999999"
FormatException: "!."
FormatException: "999909!!"
FormatException: "-"
FormatException: "9,9:9:999,,,9,,,,,,!,,,!9!!!,!"
FormatException: "!9,"
FormatException: "!.09!!0!"
FormatException: "9-;"
FormatException: ":"
FormatException: "!.!9!9!!"
NullReferenceException: null
FormatException: ":,"
FormatException: "!!"
FormatException: "9;"
问题现在是,处理所有这些情况会有多难。简单的解决方案是使用try/catch语句保护解析指令。我不确定这是否足以保证对输入的格式良好部分进行正确操作。但也许这并不需要,格式不良的输入应该导致空结果,这将使修复解决方案变得容易。
最后,这里是达到的代码覆盖率结果。请注意,我使用十进制和单一进行了正则表达式解决方案的分析,因为PEX无法检测Decimal.Parse()内部使用的一个方法。
ParseExpression(string) 100,00% 10/10 blocks
ParseSubExpression(string) 96,15% 25/26 blocks
ParseExpressionRegex(string) 95,06% 77/81 blocks
ParseExpressionRegexSingle(string) 94,87% 74/78 blocks
对我来说的结论是 - 正则表达式解决方案确实应该被优先选择。它们在设计和理解上可能有些困难,但它们比基于简单字符串操作的实现更能处理格式不正确的输入。还有要记住的一点是 - 我并没有检查返回的结果是否正确,这是另一个问题。