@Test
public void jepTest() throws ParseException {
ConfigurableParser cp = new ConfigurableParser();
cp.addSingleQuoteStrings();
Jep jep = new Jep(cp);
String expression = "'line\nbreak'";
Node node = jep.parse(expression);
System.out.println(jep.toString(node));
}
com.singularsys.jep.ParseException: Could not match text ''line'.
at com.singularsys.jep.configurableparser.Tokenizer.nextTokenMultiLine(Unknown Source)
at com.singularsys.jep.configurableparser.Tokenizer.scan(Unknown Source)
at com.singularsys.jep.configurableparser.ConfigurableParser.scan(Unknown Source)
at com.singularsys.jep.configurableparser.ConfigurableParser.parse(Unknown Source)
at com.singularsys.jep.Jep.parse(Unknown Source)
line
break
linetoo.
break
Hi Richard,
thank you for your answer. Unfortunately this approach does not work for little more sophisticated expressions.
- If the expression is "if(true, 'line\nbreak', 'else')" then the parsing fails with an exception.
The first one is crucial for me, the second one a nice to have.
- Furthermore it would be quite nice, if the parse would work with either a single or double quoted strings within an expression.
@Test
public void test() throws ParseException, EvaluationException {
// matches the start of the string
// a ' at the start of the string and no subsequent '
TokenMatcher start = new TokenMatcher() {
private static final long serialVersionUID = 1L;
@Override
public Token match(String s) throws ParseException {
if (s.startsWith("'") && s.indexOf('\'', 1) == -1) {
return new StringToken(s, s.substring(1), '\'', false);
}
return null;
}
@Override
public void init(Jep jep) { }
};
// Matcher for the end of the string
// looks for a ' somewhere in the string
TokenMatcher end = new TokenMatcher() {
private static final long serialVersionUID = 1L;
@Override
public Token match(String s) throws ParseException {
int pos = s.indexOf('\'');
if (pos >= 0) {
return new StringToken(s.substring(0, pos + 1), s.substring(0, pos), '\'', true);
}
return null;
}
@Override
public void init(Jep jep) { }
};
// Builds the result
TokenBuilder tb = new TokenBuilder() {
private static final long serialVersionUID = 1L;
@Override
public Token match(String s) throws ParseException {
return null;
}
@Override
public void init(Jep jep) { }
// builds the token, the s here will be that matched by the start, that matched by the end and all intermediate lines
// String token constructor requires the whole text matched, then the string with quotes removed, then the delimiter
@Override
public Token buildToken(String s) {
return new StringToken(s, s.substring(1, s.length() - 1), '\'', false);
}
};
// Now combine these into a MultiLineMatcher
TokenMatcher m = new MultiLineMatcher(start, end, tb);
ConfigurableParser cp = new ConfigurableParser();
cp.addSingleQuoteStrings();
cp.addTokenMatcher(m);
Jep jep = new Jep(cp);
String expression = "if(true,'line\nbreak','else')";
Node node = jep.parse(expression);
String parsedExpression = jep.toString(node);
String evaluatedExpression = jep.evaluate(node).toString();
System.out.println(parsedExpression);
System.out.println(evaluatedExpression);
}
Node node = jep.parse(expression);
com.singularsys.jep.ParseException: Could not match text 'if(true,'line'.
at com.singularsys.jep.configurableparser.Tokenizer.nextTokenMultiLine(Unknown Source)
at com.singularsys.jep.configurableparser.Tokenizer.scan(Unknown Source)
at com.singularsys.jep.configurableparser.ConfigurableParser.scan(Unknown Source)
at com.singularsys.jep.configurableparser.ConfigurableParser.parse(Unknown Source)
at com.singularsys.jep.Jep.parse(Unknown Source)
TokenMatcher m = new MultiLineMatcher(start,end,tb);
TokenMatcher m = new MultiLineMatcher(start, end, tb);
ConfigurableParser cp = new ConfigurableParser(); cp.addSingleQuoteStrings();
cp.addTokenMatcher(m);
cp.addHashComments(); cp.addSlashComments(); cp.addSingleQuoteStrings(); cp.addDoubleQuoteStrings(); cp.addWhiteSpace(); cp.addExponentNumbers(); cp.addOperatorTokenMatcher(); cp.addSymbols("(",")","[","]",","); cp.setImplicitMultiplicationSymbols("(","["); cp.addIdentifiers(); cp.addSemiColonTerminator(); cp.addWhiteSpaceCommentFilter(); cp.addBracketMatcher("(",")"); cp.addFunctionMatcher("(",")",","); cp.addListMatcher("[","]",","); cp.addArrayAccessMatcher("[","]");
IdentifierTokenMatcher.basicIndetifierMatcher
IdentifierTokenMatcher.dottedIndetifierMatcher
/**
* Creates a token matcher to accept double quoted string literals that span multi lines.
*
* @return The created token matcher.
*/
private static TokenMatcher createDoubleQuotedMultiLineMatcher() {
// Create a matcher that matches the start of the string (looks for a double quote at the start of the string).
TokenMatcher startOfDoubleQuoteTokenMatcher = new TokenMatcher() {
private static final long serialVersionUID = 1L;
@Override
public Token match(final String s) throws ParseException {
if (s.charAt(0) != '"') {
return null;
}
return new StringToken(s, s.substring(1), '"', false);
}
@Override
public void init(final Jep jep) { }
};
// Create a matcher that matches the end of the string (looks for a double quote somewhere in the string).
TokenMatcher endOfDoubleQuoteTokenMatcher = new TokenMatcher() {
private static final long serialVersionUID = 1L;
@Override
public Token match(final String s) throws ParseException {
int indexOfDoubleQuote = s.indexOf('"');
if (indexOfDoubleQuote < 0) {
return null;
}
// Check number of backslashes to decide whether or not the double quote is escaped.
while (true) {
int numberOfPrecedingBackslashes = 0;
for (int index = indexOfDoubleQuote - 1; index >= 0; index--) {
if (s.charAt(index) != '\\') {
break;
}
numberOfPrecedingBackslashes++;
}
boolean isEscaped = numberOfPrecedingBackslashes % 2 == 1;
if (!isEscaped) {
break;
}
indexOfDoubleQuote = s.indexOf('"', indexOfDoubleQuote + 1);
}
// No unescaped double quote found.
if (indexOfDoubleQuote < 0) {
return null;
}
return new StringToken(s.substring(0, indexOfDoubleQuote + 1), s.substring(0, indexOfDoubleQuote), '"', true);
}
@Override
public void init(final Jep jep) { }
};
// Create a token builder to build the complete double quoted token.
TokenBuilder doubleQuoteTokenBuilder = new TokenBuilder() {
private static final long serialVersionUID = 1L;
@Override
public Token match(final String s) throws ParseException {
return null;
}
@Override
public void init(final Jep jep) { }
@Override
public Token buildToken(final String s) {
// Builds the token, the s here will be that matched by the start, that matched by the end and all intermediate lines.
// String token constructor requires the whole text matched, then the string with quotes removed, then the delimiter.
return new StringToken(s, s.substring(1, s.length() - 1), '\"', false);
}
};
// Now combine the token matcher pair into a multi line token matcher.
return new MultiLineMatcher(startOfDoubleQuoteTokenMatcher, endOfDoubleQuoteTokenMatcher, doubleQuoteTokenBuilder);
}
/**
* Creates a token matcher to accept single quoted string literals that span multi lines.
*
* @return The created token matcher.
*/
private static TokenMatcher createSingleQuotedMultiLineMatcher() {
// Create a matcher that matches the start of the string (looks for a single quote at the start of the string).
TokenMatcher startOfSingleQuoteTokenMatcher = new TokenMatcher() {
private static final long serialVersionUID = 1L;
@Override
public Token match(final String s) throws ParseException {
if (s.charAt(0) != '\'') {
return null;
}
return new StringToken(s, s.substring(1), '\'', false);
}
@Override
public void init(final Jep jep) { }
};
// Create a matcher that matches the end of the string (looks for a single quote somewhere in the string).
TokenMatcher endOfSingleQuoteTokenMatcher = new TokenMatcher() {
private static final long serialVersionUID = 1L;
@Override
public Token match(final String s) throws ParseException {
int indexOfSingleQuote = s.indexOf('\'');
if (indexOfSingleQuote < 0) {
return null;
}
// Check number of backslashes to decide whether or not the single quote is escaped.
while (true) {
int numberOfPrecedingBackslashes = 0;
for (int index = indexOfSingleQuote - 1; index >= 0; index--) {
if (s.charAt(index) != '\\') {
break;
}
numberOfPrecedingBackslashes++;
}
boolean isEscaped = numberOfPrecedingBackslashes % 2 == 1;
if (!isEscaped) {
break;
}
indexOfSingleQuote = s.indexOf('\'', indexOfSingleQuote + 1);
}
// No unescaped single quote found.
if (indexOfSingleQuote < 0) {
return null;
}
return new StringToken(s.substring(0, indexOfSingleQuote + 1), s.substring(0, indexOfSingleQuote), '\'', true);
}
@Override
public void init(final Jep jep) { }
};
// Create a token builder to build the complete single quoted token.
TokenBuilder singleQuoteTokenBuilder = new TokenBuilder() {
private static final long serialVersionUID = 1L;
@Override
public Token match(final String s) throws ParseException {
return null;
}
@Override
public void init(final Jep jep) { }
@Override
public Token buildToken(final String s) {
// Builds the token, the s here will be that matched by the start, that matched by the end and all intermediate lines.
// String token constructor requires the whole text matched, then the string with quotes removed, then the delimiter.
return new StringToken(s, s.substring(1, s.length() - 1), '\'', false);
}
};
// Now combine the token matcher pair into a multi line token matcher.
return new MultiLineMatcher(startOfSingleQuoteTokenMatcher, endOfSingleQuoteTokenMatcher, singleQuoteTokenBuilder);
}