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

时间:2016-02-07 04:03:25

标签: java regex switch-statement

我尝试将令牌与函数中的switch语句进行匹配,其中一个令牌需要能够识别任何字符串或任何数字由下面的代码中的正则表达式定义。

基本上,是否可以针对像case "[a-z]+":

这样的案例定义正则表达式

显然我现在拥有它的方式,除非我将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;

      }
   }

4 个答案:

答案 0 :(得分:5)

不要在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列表中的条目取代了{{1}中的各个case }}。添加新的令牌类型就像将新模式及其相关实现添加到switch列表一样简单。

修改:您可以通过将上面的界面替换为类来缩短解决方案,如下所示:

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

答案 1 :(得分:2)

此解决方案受 @dbbenenlight 解决方案的启发。 试着改善它。

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 :(得分:1)

您需要2个参数:

int

更新

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;
            }

答案 3 :(得分:1)

也许这对你来说不是最好的解决方案,但一般来说你可以将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;
        }

如果您的令牌值已经是枚举,则可能(或可能不)适合在您的令牌枚举中直接使用Pattern并简单地迭代所有令牌枚举值。