我尝试将令牌与函数中的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;
}
}
答案 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并简单地迭代所有令牌枚举值。