Java 如何在switch语句中匹配正则表达式?
我试图将标记与函数中的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
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存储一个字符串会迫使您在每次通过循环时编译该模式,这是我在可能的情况下尽量避免的。