Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在switch语句中匹配正则表达式?_Java_Regex_Switch Statement - Fatal编程技术网

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

Java 如何在switch语句中匹配正则表达式?,java,regex,switch-statement,Java,Regex,Switch Statement,我试图将标记与函数中的switch语句进行匹配,其中一个标记需要能够识别下面代码中正则表达式定义的任何字符串或任何数字 基本上,是否可以针对case“[a-z]+”: 显然,按照我现在的方式,除非我将STRING或NUMBER作为参数传递,否则无法访问我的模式 public Token analyzeToken(String token) { Token tokenType = null; switch (token) { case "ST

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

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

显然,按照我现在的方式,除非我将
STRING
NUMBER
作为参数传递,否则无法访问我的模式

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;

      }
   }

您将需要两个参数:

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()) {
               // ...
            }

不要在
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;
        }
    });
}
for
循环取代了
开关
语句,而
匹配器
列表中的条目取代了
开关
中的单个
案例
。添加新的令牌类型与将新模式及其相关实现添加到
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.add(new TokenMatcher("[a-z]+", Token.STRING));
matchers.add(new TokenMatcher("[0-9]+", Token.NUMBER));
现在,您的
匹配器
初始化可以这样完成:

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.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;
    }
}
公共类标记匹配器{
私有HashMap tokenMap=新HashMap();
{
tokenMap.put(“[a-z]+”,Token.STRING);
tokenMap.put(“[0-9]+”,Token.NUMBER);
tokenMap.put(“\\(”,Token.RIGHT\u父项);
tokenMap.put(“\\”,Token.LEFT\u父项);
...
}
公共令牌匹配(字符串s){
for(字符串键:tokenMap.keySet()){
Pattern=Pattern.compile(键);
匹配器匹配器=模式匹配器;
if(matcher.matches())返回tokenMap.get(key);
}
返回令牌。未知;
}
}

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

也许这对您来说不是最好的解决方案,但通常您可以将regex-to-switch语句作为enum传递。只有当您不需要动态创建正则表达式时,这才是好的

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

如果您的令牌值已经是enum,那么直接在令牌枚举中使用模式并简单地迭代所有令牌枚举值可能(也可能不)是合适的。

问题是什么?在我的case语句中,我有“STRING”和“NUMBER”,但这不是传递给函数的令牌。那么我应该用
case
定义什么呢?这看起来像是一个在Java8中可以工作的例子,在那里你可以打开字符串literals@Gavriel我试着匹配任何字符串。用switch语句可以吗?这就是我要找的!谢谢。@dasblinkenlight,很好的解决方案,但您不认为最好有一个
Map
,其中key是
String
模式,value是
Token
?然后在match方法中,您可以迭代模式。而且代码重复次数更少。@KenBekov映射在这种情况下不会给您带来太多优势,因为您从不按模式查找。本质上,对于您的程序来说,它变成了
(模式、标记)
元组的列表。另一方面,设置类而不是接口会减少代码的重复。请看编辑。@dasblinkenlight,我们的解决方案是完全相同的(这并不奇怪,因为我的是基于你的)。只有一个区别:我将模式存储为
String
,而您将模式存储为
Pattern
类的实例。在我的代码中,只有一个
Pattern
的实例,它将在
match
方法完成后发布。@KenBekov存储一个字符串会迫使您在每次通过循环时编译该模式,这是我在可能的情况下尽量避免的。