首先根据模式创建正则表达式,即Regex对象,利用该对象的Matches方法获取公式中符合该模式的所有匹配(顺便鄙视一下.NET的命名问题,这时候你把Match当作名词还是动词用呀?)。对于每个匹配,获取我们所需要的信息,将公式项的值计算出来,用值计算替换项。

  与字符串拆分的方法比起来,使用正则表达式有很多优势。我们只需要关注感兴趣的内容(公式项),把公式中的其他内容排除在代码之外,如不必理睬运算符中是否还包含乘除,是否还包含括弧,等等。这样不仅解决了上段代码中存在的问题,还使得这个版本的代码更简洁。

  注意从每次匹配中获取分组中内容的方法。Groups[0]表示整个模式匹配到的内容,即公式项本身,如 $B'1车间一号表'。Groups[i],其中 i 大于0,则表示模式中第 i 个括弧中的内容。为了防止被序号搞晕,还可以对分组命名。

    private const string FormulaItemPattern = @"$(?<type>[B|G|J])'(?<name>.+?)'";
&nbsp;
    private double EvaluateFormula(string formula)
    {
        foreach (Match match in new Regex(FormulaItemPattern).Matches(formula))
        {

            var item = match.Groups[0].ToString();
            var type = match.Groups["type"].ToString();
            var name = match.Groups["name"].ToString();

            ...
    }

  这样修改后,我们过上了幸福的生活,直到有……

  四、产品组要求修改格式

  我们有一个神秘的组织,叫产品组。这天该组织突然发布通知,说 $ 符号已作他用,不能当作本项目的引导符,而应当用 #。而且,类型和对象名称之间应当用半角句号分割开来。原来的公式

  ($B'1车间一号表'+10-$G'一罐区二号罐'+$J'N-213号节点')*5

  应当变成这个样子的:

  (#B.'1车间一号表'+10-#G.'一罐区二号罐'+#J.'N-213号节点')*5

  不管这样的要求有没有道理,开发方面遵照执行。用了正则表达式,面对这样的修改要求,变得简单了,只需要修改公式项模式即可:

    private const string FormulaItemPattern = @"#(?<type>[B|G|J]).'(?<name>.+?)'";

  这样修改后,我们又过上了幸福的生活。

  五、总结

  实际项目中,关于公式定义的故事还有续集。公式项模式的定义,以及代码处理,也远比这里复杂。但关于正则表达式的使用,核心内容都提到了。

  再喊一遍口号吧:使用正则表达式解析字符串,可以使代码编得更为简洁,可以灵活应对情况的变化,可以使程序员的生活不那么苦逼。

  六、不算题外话

  有,玉龙问老谭:“博士,上次您说的我忘了,怎么用正则表达式表示一个或多个字符呀?”

  老谭没有回答他的问题,反问要用正则表达式做什么。玉龙说要拆分这样的字符串:ABC/XYZ,得到用斜杠分开的前后两部分。

  那用string.Split不是更简单么?玉龙则回答:“是您说的一定要用正则表达式呀?”

  老谭真不记得这样说过。