Разбор и оценка строк Java - PullRequest
       3

Разбор и оценка строк Java

0 голосов
/ 15 сентября 2011

All

Я нахожусь в процессе или переписываю некоторый код, который я написал некоторое время назад. Целью кода было вычисление даты и времени на основе строки в следующих форматах:

  • DayStart + 2hour + 1Day-2мин
  • NOW + 20day
  • MonthStart + 1month

Что займет начало дня (по местному времени), например 2011-09-15 00:00:00 BST (2011-09-15 23:00 GMT), затем прибавьте 2 часа, добавьте 1 день и вычтите 2 минуты.

Реализация на Java, и оригинальный алгоритм был довольно простым. Он просматривал каждый символ в строке и добавлялся в буфер. Затем буфер был проверен, чтобы увидеть, заканчивается ли он искомыми строками (указатель даты, например, MINUTE, HOUR, DAYSTART и т. Д.), Затем извлек число и добавил его в ArrayList, где DateOffset был простым классом с int и String. который был спецификатором даты. Вот пример кода:

// hard coded for sample
String s = "DayStart+2Hour+1Day-2Minutes";

StringBuilder sbBuffer = new StringBuilder();
String buffer;

// iterate through date string
for (char c : s.toCharArray()) {
    sbBuffer.append(c);
    buffer = sbBuffer.toString();

    // check to see the end of the buffer string is what we expect
    if (buffer.endsWith("DAYSTART")) {
        offsets.add(new DateOffset(0, "DAYSTART"));
        sbBuffer = new StringBuilder();
    } else if (buffer.endsWith("DAY") && buffer.length() > 3) {
        String numberStringPart = buffer.substring(0, buffer.length() - 3);
        numberStringPart = numberStringPart.replaceAll("[+]", "").trim();  // need as parseInt does not like the +.

        offsets.add(new DateOffset(Integer.parseInt(numberStringPart), "DAY"));
        sbBuffer = new StringBuilder();
    } ... and so on ...
    else {
    }
}

После анализа строки я перебрал ArrayList, чтобы вычислить дату и время.

Проблема с вышесказанным, вероятно, неэффективна, хотя у нас не было никаких проблем. Он также не обнаруживает никаких ошибок, поэтому вы можете ввести DayStart + 2GKGKER.

Я просто пытаюсь придумать свежие и аккуратные идеи о том, что использовать, чтобы переписать его. Я сделал небольшое регулярное выражение, но не слишком уверен, что это будет лучший маршрут.

Есть мысли?

Спасибо

Andez

Ответы [ 4 ]

3 голосов
/ 15 сентября 2011

Определите грамматику для ваших выражений. Взгляните на структуру ANTLR , которая поможет вам построить грамматику и обработать выражения.

1 голос
/ 15 сентября 2011

Woohoo, это было весело!Спасибо!: -)

public class DateExpressions {
    private Map<String, Date> dateVariables;
    private Map<String, Integer> temporalUnits;
    private Map<Character, Integer> temporalOperations;

    public static DateExpressions createInstance() {
        DateExpressions de = new DateExpressions();
        Calendar c = Calendar.getInstance();
        de.setVariable("NOW", c.getTime());

        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        de.setVariable("DayStart", c.getTime());

        c.set(Calendar.DAY_OF_MONTH, 1);
        de.setVariable("MonthStart", c.getTime());

        return de;
    }

    public DateExpressions() {
        this.dateVariables = new HashMap<String, Date>();
        this.temporalUnits = new HashMap<String, Integer>();
        this.temporalUnits.put("Second", Calendar.SECOND);
        this.temporalUnits.put("Minute", Calendar.MINUTE);
        this.temporalUnits.put("Hour", Calendar.HOUR_OF_DAY);
        this.temporalUnits.put("Day", Calendar.DATE);
        this.temporalUnits.put("Month", Calendar.MONTH);
        this.temporalUnits.put("Year", Calendar.YEAR);

        this.temporalOperations = new HashMap<Character, Integer>();
        this.temporalOperations.put('+', 1);
        this.temporalOperations.put('-', -1);
    }

    public void setVariable(String key, Date value) {
        this.dateVariables.put(key, value);
    }

    public Date parseExpression(String expr) throws IOException {
        StringReader sr = new StringReader(expr);
        String s;
        int n;
        char c;

        int offset;
        int unit;
        int op = 1;

        Calendar base = null;
        StringBuilder sb1 = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        while ((n = sr.read()) != -1) {
            c = (char) n;

            if (base == null && temporalOperations.containsKey(c)) {
                s = sb2.toString();
                if (!dateVariables.containsKey(s)) {
                    throw new IOException("Unknown variable '" + s + "' used");
                }

                base = Calendar.getInstance();
                base.setTime(dateVariables.get(sb2.toString()));
                op = temporalOperations.get(c);

                sb1.setLength(0);
                sb2.setLength(0);
            } else if (temporalOperations.containsKey(c)) {
                if (!temporalUnits.containsKey(sb2.toString())) {
                    throw new IOException(
                            "Parse error: unknown temporal unit used '"
                                    + sb2.toString() + "'");
                }

                offset = Integer.parseInt(sb1.toString());
                unit = temporalUnits.get(sb2.toString());

                base.add(unit, op * offset);

                op = temporalOperations.get(c);
                sb1.setLength(0);
                sb2.setLength(0);
            } else if (Character.isDigit(c)) {
                sb1.append(c);
            } else {
                sb2.append(c);
            }
        }

        if (!temporalUnits.containsKey(sb2.toString())) {
            throw new IOException("Parse error: unknown temporal unit used '"
                    + sb2.toString() + "'");
        }

        offset = Integer.parseInt(sb1.toString());
        unit = temporalUnits.get(sb2.toString());

        base.add(unit, op * offset);

        return base.getTime();
    }

    public static void main(String[] args) throws IOException {
        DateExpressions de = DateExpressions.createInstance();
        System.out.println(de.parseExpression("DayStart+2Hour+1Day-2Minute"));
        System.out.println(de.parseExpression("NOW+20Day"));
        System.out.println(de.parseExpression("MonthStart+1Month"));
    }
}
1 голос
/ 15 сентября 2011

Если вы после быстрых экспериментов, иногда грамотный API в сочетании с компиляцией на лету является простым способом.

Итак, ваш пример может выглядеть (при условии соответствующего статического импорта)

daystart().plus()
    .hours(2).plus()
    .days(1).minutes(2)

или даже (в качестве основных единиц приведены миллисекунды)

daystart() + hours(2) + days(1) - minutes(2)
0 голосов
/ 15 сентября 2011

Regex, кажется, лучшая ставка для такого сценария.Хотя я озадачен, почему вы хотите интерпретировать строки таким образом, а не иметь сложные API.

...