Using jparsec, I'm trying to parse numbers that may or may not be negative:
@Test
public void canParseIntegerValues() {
assertEquals(0, ValueParser.PARSER.parse("0"));
assertEquals(276, ValueParser.PARSER.parse("276"));
assertEquals(-3874, ValueParser.PARSER.parse("-3874"));
}
I've not been able to figure out how to declare PARSER
. I've tried:
private static final Parser<Integer> INTEGER_VALUE_PARSER = Terminals.IntegerLiteral.TOKENIZER
.map(new Map<Fragment, Integer>() {
@Override
public Integer map(Fragment from) {
return Integer.valueOf(from.text());
}
});
This doesn't work because Terminals.IntegerLiteral.TOKENIZER
does not accommodate a minus sign. Next, I tried:
private static final Parser<Integer> INTEGER_VALUE_PARSER = Parsers.sequence(
Scanners.string("-").optional().token(),
Terminals.IntegerLiteral.TOKENIZER
.map(new Map<Fragment, Integer>() {
@Override
public Integer map(Fragment from) {
return Integer.valueOf(from.text());
}
}));
This also doesn't work because the negative sign is discarded and my map function never sees it.
Can anyone tell me how to correctly parse integers that may or may not be positive using jparsec?
EDIT: I found a way to do it, but I find it hard to believe that this is the best way:
private static final Parser<Integer> INTEGER_VALUE_PARSER = Parsers.sequence(
Scanners.string("-").many(),
Terminals.IntegerLiteral.TOKENIZER,
new Map2<List<Void>, Fragment, Integer>() {
@Override
public Integer map(List<Void> from1, Fragment from2) {
boolean isNegative = (from1.size() % 2) == 1;
if (isNegative) {
return -1 * Integer.valueOf(from2.text());
} else {
return Integer.valueOf(from2.text());
}
}
});
You can have a look at the Calculator
class in jparsec's examples: https://github.com/abailly/jparsec/blob/master/jparsec-examples/src/main/java/org/codehaus/jparsec/examples/calculator/Calculator.java Here negative integers are handled as integers on which a prefix -
operator has been applied.
Alternatively you can simply declare a pattern comprising your minus sign:
public void test() {
Pattern regex = Patterns.regex("-?\\d+");
Parser<Integer> integer = Scanners.pattern(regex, "Integer").source().map(new Map<String, Integer>() {
@Override
public Integer map(String s) {
return Integer.parseInt(s);
}
});
assertEquals(-42, (int) integer.parse("-42"));
}
HTH
Arnaud