How to parse Dates and Datetimes and Date*Ranges? #88
-
|
Hi folks, I am trying to use dot-parse to write a small search engine. Following the example I wanted to add some special parsers. So my code currently looks like this: Set<String> keywords = Set.of("AND", "OR", "NOT");
// A search term is either quoted, or unquoted (but cannot be a keyword)
Parser<SearchCriteria.Term> unquoted = word().suchThat(w -> !keywords.contains(w), "search term").map(SearchCriteria.Term::new);
Parser<SearchCriteria.Term> quoted = Parser.quotedStringWithEscapes('"', chars(1)).map(SearchCriteria.Term::new);
Parser<SearchCriteria.RangeDigits> rangeDigits = Parser.digits().notFollowedBy(":").atLeastOnceDelimitedBy("..").between("[", "]").map(list -> new SearchCriteria.RangeDigits(list.get(0), list.get(1)));
// Leaf-level search term can be a quoted, unquoted term, or a sub-criteria inside parentheses.
// They are then grouped by the boolean operators.
parser = Parser.define(
sub -> new OperatorTable<SearchCriteria>()
.prefix(word("NOT").thenReturn(SearchCriteria.Not::new), 30)
.leftAssociative(word("AND").thenReturn(SearchCriteria.And::new), 20)
.leftAssociative(word("OR").thenReturn(SearchCriteria.Or::new), 10)
.build(Parser.anyOf(rangeDigits, unquoted, quoted, sub.between("(", ")"))));It works so far. Similar to Any ideas?! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
|
IIUC, the digit range looks like this: Then it shouldn't be ambiguous, simply use Btw, I wouldn't use Parser.sequence(
digits().followedBy(".."),
digits(),
DigitsRange::new);Similarly, something like this for date range: Parser<Integer> digits(int n) {
return Parser.digits().suchThat(s.length() == n, n + " digits").map(Integer::parseInt);
}
Parser<LocalDate> d = sequence(
sequence(digits(2).followedBy("."), digits(2), DayAndMonth::new).followedBy("."),
digits(4),
(dm, y) -> new LocalDate(y, dm.month(), dm.day()));
Parser<DateRange> sequence( d.followedBy(".."), d, DateRange::new).between("[", "]"); |
Beta Was this translation helpful? Give feedback.
-
|
Or if you don't like the nested Parser<LocalDate> ld = Parser.digits()
.atLeastOnceDelimitedBy(".")
.suchThat(list ->
list.size() == 3 && list.get(0).length() == 2 && list.get(1).length() == 2 && list.get(2).length() == 4,
"dd.mm.yyyy")
.map(list -> new LocalDate(Integer.parseInt(list.get(2)), Integer.parseInt(list.get(1)), Integer.parseInt(list.get(0))));
Parser<DateRange> dateRange = Parser.sequence(ld.followedBy(".."), ld, DateRange::new).between("[", "]"); |
Beta Was this translation helpful? Give feedback.
-
|
I just added a Parser<Integer> digits(int n) {
return Parser.digits().suchThat(s.length() == n, n + " digits").map(Integer::parseInt);
}
Parser<LocalDate> ld = Parser.sequence(
digits(2).followedBy("."), digits(2).followedBy("."), digits(4),
(dd, mm, yyyy) -> new LocalDate(yyyy, mm, dd)); |
Beta Was this translation helpful? Give feedback.
Or if you don't like the nested
sequence()call, usingatLeastOnceDelimitedBy()for the date range is an option too: