如何匹配 switch 语句中的正则表达式?
How can I match a regex in a switch statement?
我正在尝试将标记与函数中的 switch 语句进行匹配,其中一个标记需要能够识别 any 字符串或 any 由以下代码中的正则表达式定义的数字。
基本上,是否可以针对 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;
}
}
您需要 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()) {
// ...
}
不要在 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
列表中的条目取代了 case
中的单个 case
=14=]。添加新的令牌类型就像向 matchers
列表中添加新模式及其相关实现一样简单。
编辑: 您可以通过将上面的界面替换为 class 来缩短解决方案,如下所示:
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;
}
}
改进:更容易添加新令牌,重复代码更少,不需要额外的接口。
也许这不是您的最佳解决方案,但通常您可以将正则表达式作为枚举传递给 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 语句的 switch 了。
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 枚举值可能(或可能不合适)。
我正在尝试将标记与函数中的 switch 语句进行匹配,其中一个标记需要能够识别 any 字符串或 any 由以下代码中的正则表达式定义的数字。
基本上,是否可以针对 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;
}
}
您需要 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()) {
// ...
}
不要在 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
列表中的条目取代了 case
中的单个 case
=14=]。添加新的令牌类型就像向 matchers
列表中添加新模式及其相关实现一样简单。
编辑: 您可以通过将上面的界面替换为 class 来缩短解决方案,如下所示:
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;
}
}
改进:更容易添加新令牌,重复代码更少,不需要额外的接口。
也许这不是您的最佳解决方案,但通常您可以将正则表达式作为枚举传递给 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 语句的 switch 了。
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 枚举值可能(或可能不合适)。