I'm trying to match tokens against a switch statement in a function, and one of those tokens needs to be able to identify any string or any numbers defined by the regex in the code below.
Basically, is it possible to define a regex against a case like case "[a-z]+":
Clearly the way I have it now, my pattern is not reachable unless I pass STRING
or NUMBER
as an argument.
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;
}
}
“Smart alec. How do I add a switch statement?” she asked. “You need to type the word switch and use the regex switched parameter. Then you use the Get-Content command that you used yesterday to read the content from all your files. Next, you open and close a set of curly brackets.”
The -Regex parameter allows switch statements to perform regular expression matching against conditions. switch -Regex ('Condition') { 'Con\D+ion' {'One or more non-digits'} 'Conditio*$' {'Zero or more "o"'} 'C.ndition' {'Any single char.'} '^C\w+ition$' {'Anchors and one or more word chars.'} 'Test' {'No match'} }
I think the switch statement evaluates (switchexp == caseexp), so using a regex as a caseexp does not work as intended - it tests if the switchexp IS the regex instead of if the regex matches the switchexp. A switch actually performs === tests not == tests.
One of them is with a switch. The switch statement allows you to provide a variable and a list of possible values. If the value matches the variable, then its scriptblock is executed. For this example, the value of $day matches one of the numeric values, then the correct name is assigned to $result.
Don't do it in a switch
statement, do it in a conditional or better yet, in a loop:
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;
}
});
}
Now you can do this:
static Token match(String s) {
for (TokenMatcher m : matchers) {
Token t = m.match(s);
if (t != null) {
return t;
}
}
return TOKEN.UNKNOWN;
}
The for
loop has taken place of the switch
statement, while the entries in the matchers
list have taken place of the individual case
s in the switch
. Adding new token types is as simple as adding new patterns and their associated implementations to the matchers
list.
Edit: You could make the solution shorter by replacing the interface above with a class, like this:
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;
}
}
Now your matchers
initialization could be done like this:
matchers.add(new TokenMatcher("[a-z]+", Token.STRING));
matchers.add(new TokenMatcher("[0-9]+", Token.NUMBER));
This solution inspired by solution of @dasblinkenlight. Just attempt to improve it.
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;
}
}
Improvements: easier to add new token, less repeated code, don't need extra interfaces.
You'll need 2 parameters:
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;
}
update:
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()) {
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With