重构一系列模式匹配

时间:2011-04-15 13:34:13

标签: java regex refactoring

我有以下代码(缩写为示例):

while (reader.ready()) {
    String line = reader.readLine();

    Matcher responseCodeMatcher = responseCodePattern.matcher(line); 
    if (responseCodeMatcher.matches()) {
        responseCode = Integer.parseInt(responseCodeMatcher.group(1));
        continue;
    }

    Matcher cacheControlMatcher = cacheControlPattern.matcher(line); 
    if (cacheControlMatcher.matches()) {
        cacheControl = CacheControl.parseString(responseCodeMatcher.group(1));
        continue;
    }

        ...

}

模式都是类的静态最终成员。 所以我有一堆模式,我想找出每一行,如果它匹配其中一个,如果是这样 - 做一些事情(从模式到模式的变化)。你能想出一种以某种方式很好地重构它的方法吗?也许是我过去的模式集合(如果匹配,我怎么知道该怎么做?)或其他一些想法。

3 个答案:

答案 0 :(得分:2)

因为到目前为止没有人回答,我会,虽然我不懂Java 在C#中,我将创建一个元组列表。元组的第1项是要检查的模式,第2项是一个匿名方法,它包含要执行的模式特定代码。在C#中,它看起来像这样:

var patterns = new List<Tuple<Pattern, Action<Matcher>>>();
patterns.Add(Tuple.Create(responseCodePattern, matcher =>
    {
        responseCode = Integer.parseInt(matcher.group(1));
    }));

patterns.Add(Tuple.Create(cacheControlPattern, matcher =>
    {
        cacheControl = CacheControl.parseString(matcher.group(1));
    }));

while (reader.ready()) {
    String line = reader.readLine();
    foreach(var tuple in patterns)
    {
        Matcher matcher = tuple.Item1.matcher(line);
        if(matcher.matches())
        {
            tuple.Item2(matcher);
            break;
        }
    }
}

我不知道,如果这对Java家伙有任何意义,尤其是lambda语法...请问,如果没有: - )

答案 1 :(得分:2)

我最终以下面的方式进行重构。我创建了一个班级HttpPatterns

package cs236369.proxy.types;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public enum HttpPatterns {
    RESPONSE_CODE("^HTTP/1\\.1 (\\d+) .*$"),
    CACHE_CONTROL("^Cache-Control: (\\w+)$"),
    HOST("^Host: (\\w+)$"),
    REQUEST_HEADER("(GET|POST) ([^\\s]+) ([^\\s]+)$"),
    ACCEPT_ENCODING("^Accept-Encoding: .*$"),
    CONTENT_ENCODING("^Content-Encoding: ([^\\s]+)$");

    private final Pattern pattern;

    HttpPatterns(String regex) {
        pattern = Pattern.compile(regex);
    }

    public boolean matches(String expression) {
        return pattern.matcher(expression).matches();
    }

    public Object process(String expression) {
        Matcher matcher = pattern.matcher(expression);
        if (!matcher.matches()) {
            throw new RuntimeException("Called `process`, but the expression doesn't match. Call `matches` first.");
        }

        if (this == RESPONSE_CODE) {
            return Integer.parseInt(matcher.group(1));
        } else if (this == CACHE_CONTROL) {
            return CacheControl.parseString(matcher.group(1));
        } else if (this == HOST) {
            return matcher.group(1);
        } else if (this == REQUEST_HEADER) {
            return new RequestHeader(RequestType.parseString(matcher.group(1)), matcher.group(2), matcher.group(3));
        } else if (this == CONTENT_ENCODING) {
            return ContentEncoding.parseString(matcher.group(1));
        } else { //never happens
            return null;
        }
    }


}

我这样使用它:

String line;
            while ((line = reader.readLine()) != null) {

                if (HttpPatterns.CACHE_CONTROL.matches(line)) {
                    cacheControl = (CacheControl) HttpPatterns.RESPONSE_CODE.process(line);
                } else if (HttpPatterns.REQUEST_HEADER.matches(line)) {
                    requestHeader = (RequestHeader) HttpPatterns.REQUEST_HEADER.process(line);
                } else if (HttpPatterns.HOST.matches(line)) {
                    requestHost = (String) HttpPatterns.HOST.process(line);
                } else if (HttpPatterns.ACCEPT_ENCODING.matches(line)) {
                    continue;
                } else if (line.isEmpty()) {
                    break;
                }
                fullRequest += "\r\n" + line;
            }

我不喜欢我必须投出一切,但这是我迄今为止找到的最佳解决方案。

答案 2 :(得分:0)

好的,这是我的简短回答:这不是一个语言问题,到目前为止,这里的答案和评论都非常偏离基础。所有语言,无论多么具体,都包括类型。这是一个关于如何检测这些类型然后调用适当的相应操作的问题。答案是四人帮中的几种模式。

首先,对于解析部分,我建议您将其视为中介。动作应该对模式或文件一无所知,同样,动作的知识也不应该注入触发上下文。你可以将这个东西称为解析器,探测器等等,但该类的核心是将模式映射到适当的动作。

在动作方面,使用的模式当然是命令模式。使用命令时有很多可能性。如果你不需要上下文,那么命令非常简单,它只有一个执行方法。如果您需要传递一些将要改变的上下文,您可以模拟命令或动态创建新命令然后调用它们。