package edu.stanford.nlp.sempre; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Parse strings representing date ranges such as "20th century". * The result has the form (and (< ...) (>= ...)). * * Currently only supports patterns like "1990's" and "1800s" * * @author ppasupat */ public class DateRangeFn extends SemanticFn { @Override public DerivationStream call(Example ex, Callable c) { return new LazyDateRangeFnDerivs(ex, c); } public static class LazyDateRangeFnDerivs extends MultipleDerivationStream { Example ex; Callable c; int index = 0; List<Formula> formulas; public LazyDateRangeFnDerivs(Example ex, Callable c) { this.ex = ex; this.c = c; } @Override public Derivation createDerivation() { if (formulas == null) populateFormulas(); if (index >= formulas.size()) return null; Formula formula = formulas.get(index++); return new Derivation.Builder().withCallable(c) .formula(formula).type(SemType.numberType).createDerivation(); } private static final Pattern YEAR_RANGE = Pattern.compile("^(\\d+0+)\\s*'?s$"); // TODO: Handle more cases private void populateFormulas() { formulas = new ArrayList<>(); String query = c.childStringValue(0); Matcher matcher = YEAR_RANGE.matcher(query); if (!matcher.matches()) return; int year = Integer.parseInt(matcher.group(1)), range = 10; while (year % range == 0) { // Put "<" before ">=" to keep the children of MergeFormula sorted formulas.add(new MergeFormula(MergeFormula.Mode.and, new JoinFormula(new ValueFormula<Value>(new NameValue("<")), new ValueFormula<>(new NumberValue(year + range))), new JoinFormula(new ValueFormula<Value>(new NameValue(">=")), new ValueFormula<>(new NumberValue(year))))); range *= 10; } } } }