繁体   English   中英

如何在switch语句中匹配正则表达式?

[英]How can I match a regex in a switch statement?

我正在尝试将标记与函数中的switch语句进行匹配,并且这些标记之一需要能够识别以下代码中的正则表达式定义的任何字符串或任何数字。

基本上,是否可以针对case "[az]+":这样的case "[az]+":定义一个正则表达式case "[az]+":

显然,我现在有这种方式,除非将STRINGNUMBER作为参数传递,否则无法访问我的模式。

public Token analyzeToken(String token) {
      Token tokenType = null;     

      switch (token) {

         case "STRING":
            Pattern p = Pattern.compile("[a-z]+");
            Matcher m = p.matcher(token);
            if(m.matches()) {
               tokenType = Token.STRING;
               break;
            }
         case "NUMBER":
            Pattern p = Pattern.compile("[0-9]+");
            Matcher m = p.matcher(token);
            if(m.matches()) {
               tokenType = Token.NUMBER;
               break;

         case "(":
            tokenType = Token.LEFT_PAREN;
            break;
         case ")":
            tokenType = Token.RIGHT_PAREN;
            break;
         case ".":
            tokenType = Token.PERIOD;
            break;
         case ":":
            tokenType = Token.COLON;
            break;
         case ";":
            tokenType = Token.SEMICOLON;

         default:
            tokenType = TOKEN.UNKNOWN;
            break;

      }
   }

不要在switch语句中执行此操作,而应在循环中有条件或更好的执行此操作:

private interface TokenMatcher {
    Token match(String s);
}
static List<TokenMatcher> matchers = new ArrayList<>();
static {
    final Pattern strPattern = Pattern.compile("[a-z]+");
    final Pattern numPattern = Pattern.compile("[0-9]+");
    matchers.add( new TokenMatcher {
        public Token match(String s) {
            Matcher m = strPattern.matcher(s);
            return m.matches() ? Token.STRING : null;
        }
    });
    matchers.add( new TokenMatcher {
        public Token match(String s) {
            Matcher m = numPattern.matcher(s);
            return m.matches() ? Token.NUMBER : null;
        }
    });
}

现在您可以执行以下操作:

static Token match(String s) {
    for (TokenMatcher m : matchers) {
        Token t = m.match(s);
        if (t != null) {
            return t;
        }
    }
    return TOKEN.UNKNOWN;
}

for循环已发生在switch语句中,而matchers列表中的条目已发生在switch中的单个case 添加新令牌类型就像将新模式及其关联的实现添加到matchers列表一样简单。

编辑:您可以通过将上面的接口替换为一个类来缩短解决方案,如下所示:

private static final class TokenMatcher {
    private final Pattern p;
    private final Token t;
    public TokenMatcher(String pString, Token t) {
        p = Pattern.compile(pString);
        this.t = t;
    }
    public Token match(String s) {
        Matcher m = p.matcher(s);
        return m.matches() ? t: null;
    }
}

现在,您的matchers初始化可以像这样完成:

matchers.add(new TokenMatcher("[a-z]+", Token.STRING));
matchers.add(new TokenMatcher("[0-9]+", Token.NUMBER));

此解决方案受@dasblinkenlight解决方案的启发。 只是尝试改善它。

public class TokenMatcher{

    private HashMap<String, Token> tokenMap = new HashMap<String, Token>();
    {
        tokenMap.put("[a-z]+", Token.STRING);
        tokenMap.put("[0-9]+", Token.NUMBER);
        tokenMap.put("\\(", Token.RIGHT_PARENT);
        tokenMap.put("\\)", Token.LEFT_PARENT);
        ...
    }


    public Token match(String s){
        for(String key : tokenMap.keySet()){
            Pattern pattern = Pattern.compile(key);
            Matcher matcher = pattern.matcher(s);
            if(matcher.matches()) return tokenMap.get(key);
        }
        return Token.UNKNOWN;
    }
}

改进:更容易添加新令牌,减少重复代码,不需要额外的接口。

您将需要2个参数:

public Token analyzeToken(String token, String string) {
      Token tokenType = null;     
      switch (token) {
         case "STRING":
            Pattern p = Pattern.compile("[a-z]+");
            Matcher m = p.matcher(string); // match the string, not the token!
            if(m.matches()) {
               tokenType = Token.STRING;
               break;
            }

更新:

public Token analyzeToken(String regex, String string) {
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(string); // match the string, not the token!
            if(m.matches()) {
               // ...
            }

也许这不是您的最佳解决方案,但是通常您可以将regex作为枚举传递给switch语句。 仅当不需要动态创建正则表达式时,这样做才是好的。

enum PatternCase {
    pattern1("regexp1"),
    pattern2("regexp2"),
    pattern3("regexp3"),
    pattern4("regexp4", Pattern.CASE_INSENSITIVE),
    ;
    final Pattern pattern;
    PatternCase(String regExp) { pattern = Pattern.compile(regExp); }
    PatternCase(String regExp, int flags) { pattern = Pattern.compile(regExp, flags); }
}

然后,您可以使用正则表达式作为case语句来完全正常工作。

        Matcher matcher = null;
        PatternCase matchedPatternCase = null;  // Or use some default value to avoid null checks.

        // Match only these patterns and match them in this effective order.
        for (PatternCase patternCase : new PatternCase[]{ PatternCase.pattern3, PatternCase.pattern1 }) {
            matcher = patternCase.pattern.matcher(text);
            if (matcher.find()) {
                matchedPatternCase = patternCase;
                break;
            }
        }

        if (matchedPatternCase != null) switch (matchedPatternCase) {
            case pattern1:
                System.out.println(matcher.group());
                break;
            case pattern3:
                do { System.out.println(matcher.group()); } while (matcher.find());
                break;
            default:
                break;
        }

如果您的Token值已经是枚举,则直接在您的Token枚举中使用Pattern并简单地遍历所有Token枚举值可能是(也可能不是)合适的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM