加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 正则表达式,捕获组和单元测试的良好设计

发布时间:2020-12-15 21:51:19 所属栏目:百科 来源:网络整理
导读:在一个项目中,我正在尝试使用正则表达式来区分各种类型的句子,并将它们映射到处理这些句子的函数. 这些句子处理函数中的大多数都从句子本身获取参数,由正则表达式中的捕获组解析. 例如:“我为2个cookie支付了20美元”与我的解析树(字典)中的一个正则表达式
在一个项目中,我正在尝试使用正则表达式来区分各种类型的句子,并将它们映射到处理这些句子的函数.

这些句子处理函数中的大多数都从句子本身获取参数,由正则表达式中的捕获组解析.

例如:“我为2个cookie支付了20美元”与我的解析树(字典)中的一个正则表达式相匹配.正则表达式将提取20美元作为组“价格”,将2作为组“金额”匹配.目前我正在映射到正确的Handler函数并调用它如下:

foreach(KeyValuePair<Regex,Type> pair in sentenceTypes)
{
    Match match = pair.Key.Match(text);
    if(match.Success)
    {
        IHandler handler = handlerFactory.CreateHandler(pair.Value);
        output = handler.Handle(match);
    }
}

简单处理程序类的示例.

public class NoteCookiePriceHandler
    {
        public string Handle(Match match)
        {
            double payment = Convert.ToDouble(match.Result("${payment}"));
            int amount = Convert.ToInt32(match.Result("${amount}"));

            double price = payment / amount;
            return "The price is $" + price;
        }
    }

我试图用Moq设置一些单元测试来帮助,当我意识到我实际上不能模拟Match对象,也不是正则表达式.考虑到这一点,设计似乎有些缺陷,因为我依赖于命名组被正确解析并传递给Handler类而没有良好的接口.

我正在寻找有关更有效的设计的建议,用于正确地将参数传递给映射的处理函数/类,因为传递Match对象似乎有问题.

如果做不到这一点,任何帮助找出有效模拟正则表达式或匹配的方法都会受到赞赏,至少可以帮助我解决我的短期问题.它们都缺少默认构造函数,因此我很难让Moq创建它们的对象.

编辑:我最后通过为我的匹配组传递字符串字典而不是(不可Moq-able)匹配对象本身来解决至少模拟问题.我对这个解决方案并不是特别满意,所以建议仍然会受到赞赏.

foreach(KeyValuePair<Regex,Type> pair in sentenceTypes)
        {
            match = pair.Key.Match(text);
            if(match.Success)
            {
                IHandler handler= handlerFactory.CreateHandler(pair.Value);
                foreach (string groupName in pair.Key.GetGroupNames())
                {
                    matchGroups.Add(groupName,match.Groups[groupName].Value);
                }
                interpretation = handler.Handle(matchGroups);

解决方法

避免糟糕设计的一种方法是从良好设计的原则开始,而不仅仅是您希望解决的问题.这是测试驱动开发在转换代码质量方面如此强大的原因之一.这种思维方式在TDD之前确实存在,但名称为:按合同设计.请允许我证明:

您希望理想的处理程序看起来像什么?这个怎么样:

interface IHandler {
    String handle();
}

执行:

public class NoteCookiePriceHandler : IHandler
{  
    private double payment;
    private int amount;

    public NoteCookiePriceHandler(double payment,int amount) {
        this.payment = payment;
        this.amount = amount;
    }

    public String handle() {
        return "The price is $" + payment / amount;
    }
}

现在从这个理想的设计开始,也许是对这个设计的测试.如何才能将句子的句子输入发送给处理程序?那么,计算机科学中的所有问题都可以通过另一层间接解决.假设句子解析器不直接创建处理程序,而是使用工厂创建一个:

interface HandlerFactory<T> where T: IHandler  {
    T getHandler(KeyValuePair<String,String> captureGroups);
}

然后,您可以为每个处理程序创建一个工厂,但很快您就会找到创建通用工厂的方法.例如,使用反射可以将捕获组名称与构造函数参数进行匹配.根据构造函数参数的数据类型,您可以自动让通用处理程序工厂将字符串转换为正确的数据类型.通过创建一些假处理程序并要求工厂使用一些键值对字符串输入填充它们,这一切都可以轻松测试.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读