RRULE для удобочитаемого текста

Я хочу сгенерировать удобочитаемый текст (естественный язык) из строки RRULE (RFC2445) . Я погуглил, но нашел только библиотеку JavaScript (rrule.js), которая может генерировать такой текст. Но мне нужна эта функциональность в Android (Java).

Есть ли такая библиотека, написанная на Java? Если нет, я слышал о паре движков JavaScript в Java (например, Rhino). Но я очень беспокоюсь о производительности своего приложения для Android, потому что кажется, что эти движки немного тяжеловаты.


person frogatto    schedule 26.07.2014    source источник


Ответы (3)


Используйте WebView и rrule.js внутри, чтобы получить результат. См. этот ответ: Как вызвать javascript из Android?

person imsky    schedule 01.08.2014
comment
Если вас интересует готовая к использованию библиотека Java -› github.com/aditosoftware/rrule-parser - person rajugautam; 19.07.2019

Вместо того, чтобы раздувать свое приложение ненужными js, вы можете либо написать свой собственный класс, который сделает это за вас, либо использовать этот, который я написал. Это работало для всех вариантов использования, которые я тестировал, но если вы обнаружите, что с ним что-то не так, сообщите мне. Он использует JodaTime, но может быть настроен для любого другого объекта времени. Он также может адаптироваться к локализации (хотя у меня еще не было возможности это проверить). Если вам нужно больше языков, просто добавьте их в метод Strings.init().

package com.rexios.wealthprojection;

import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.ISODateTimeFormat;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by adelory on 7/31/2017.
 */

public class ReadableRRule {

    public static String getReadableRRule(String rrule) throws TextParseException {
        return getReadableRRule(rrule, true);
    }

    public static String getReadableRRule(String rrule, boolean capitalize) throws TextParseException {
        Strings.init(Locale.getDefault().getLanguage());

        HashMap<String, String> attributes = new HashMap<>();
        try {
            String[] attrArray = rrule.replace("RRULE:", "").split("[=;]");

            String key = "";
            String value = "";
            for (String s : attrArray) {
                if (key.isEmpty()) {
                    key = s;
                    continue;
                }
                if (value.isEmpty()) {
                    value = s;
                }

                attributes.put(key, value);
                key = "";
                value = "";
            }

            String interval = "";
            String freq = "";
            String byDay = "";
            String until = "";
            String count = "";
            for (Map.Entry<String, String> entry : attributes.entrySet()) {
                if (entry.getKey().equals("FREQ")) {
                    freq = entry.getValue();
                } else if (entry.getKey().equals("UNTIL")) {
                    until = DateTimeFormat.shortDate().print(ISODateTimeFormat.basicDateTimeNoMillis().parseLocalDate(entry.getValue()));
                } else if (entry.getKey().equals("INTERVAL")) {
                    interval = entry.getValue();
                } else if (entry.getKey().equals("COUNT")) {
                    count = entry.getValue();
                } else if (entry.getKey().equals("BYDAY")) {
                    // TODO: Make this work for monthly stuff
                    byDay = entry.getValue();

                    int num = 0;
                    Matcher matcher = Pattern.compile(".?\\d+").matcher(byDay);
                    if (matcher.find()) {
                        String temp = matcher.group();
                        num = Integer.parseInt(temp);
                        byDay = byDay.replace(temp, "");
                    }

                    boolean abbreviate = true;
                    if (byDay.length() == byDay.replace(",", "").length()) abbreviate = false;
                    byDay = byDay.replace(",", ", ");
                    byDay = byDay.replace("MO", abbreviate ? getShortDayName(0) : getFullDayName(0));
                    byDay = byDay.replace("TU", abbreviate ? getShortDayName(1) : getFullDayName(1));
                    byDay = byDay.replace("WE", abbreviate ? getShortDayName(2) : getFullDayName(2));
                    byDay = byDay.replace("TH", abbreviate ? getShortDayName(3) : getFullDayName(3));
                    byDay = byDay.replace("FR", abbreviate ? getShortDayName(4) : getFullDayName(4));
                    byDay = byDay.replace("SA", abbreviate ? getShortDayName(5) : getFullDayName(5));
                    byDay = byDay.replace("SU", abbreviate ? getShortDayName(6) : getFullDayName(6));

                    if (num != 0) {
                        String numText = "";
                        switch (num) {
                            case -1:
                                numText = Strings.last;
                                break;

                            case 1:
                                numText = Strings.first;
                                break;

                            case 2:
                                numText = Strings.second;
                                break;

                            case 3:
                                numText = Strings.third;
                                break;

                            case 4:
                                numText = Strings.fourth;
                                break;
                        }

                        byDay = "(" + Strings.on + " " + Strings.every + " " + numText + " " + byDay + ")";
                    } else {
                        byDay = Strings.on + " " + byDay;
                    }
                }
            }

            if ((interval.isEmpty() || interval.equals("1")) && byDay.length() - byDay.replace(",", "").length() == 6) {
                freq = "DAILY";
                byDay = "";
            }

            String readableRRule = "";
            switch (freq) {
                case "DAILY":
                    if (interval.isEmpty() || interval.equals("1")) {
                        readableRRule += capitalize ? capitalize(Strings.daily) : Strings.daily;
                    } else {
                        readableRRule += capitalize ? capitalize(Strings.every) : Strings.every;
                        readableRRule += " " + interval + " " + Strings.days;
                    }
                    break;
                case "WEEKLY":
                    if (interval.isEmpty() || interval.equals("1")) {
                        readableRRule += capitalize ? capitalize(Strings.weekly) : Strings.weekly;
                    } else {
                        readableRRule += capitalize ? capitalize(Strings.every) : Strings.every;
                        readableRRule += " " + interval + " " + Strings.weeks;
                    }
                    break;
                case "MONTHLY":
                    if (interval.isEmpty() || interval.equals("1")) {
                        readableRRule += capitalize ? capitalize(Strings.monthly) : Strings.monthly;
                    } else {
                        readableRRule += capitalize ? capitalize(Strings.every) : Strings.every;
                        readableRRule += " " + interval + " " + Strings.months;
                    }
                    break;
                case "YEARLY":
                    if (interval.isEmpty() || interval.equals("1")) {
                        readableRRule += capitalize ? capitalize(Strings.yearly) : Strings.yearly;
                    } else {
                        readableRRule += capitalize ? capitalize(Strings.every) : Strings.every;
                        readableRRule += " " + interval + " " + Strings.years;
                    }
                    break;
            }

            if (!byDay.isEmpty()) {
                readableRRule += " " + byDay;
            }

            if (!until.isEmpty()) {
                readableRRule += "; " + Strings.until + " " + until;
            }

            if (!count.isEmpty()) {
                if (count.equals("1")) {
                    readableRRule += "; " + Strings.four + " " + Strings.one + " " + Strings.time;
                } else {
                    readableRRule += "; " + Strings.four + " " + count + " " + Strings.times;
                }
            }

            return readableRRule;
        } catch (Exception e) {
            e.printStackTrace();
            throw new TextParseException();
        }
    }

    // Get day of week Monday-Sunday (0-6)
    private static String getFullDayName(int day) {
        Calendar c = Calendar.getInstance();
        c.set(2011, 7, 1, 0, 0, 0);
        c.add(Calendar.DAY_OF_MONTH, day);
        return String.format("%tA", c);
    }

    private static String getShortDayName(int day) {
        Calendar c = Calendar.getInstance();
        c.set(2011, 7, 1, 0, 0, 0);
        c.add(Calendar.DAY_OF_MONTH, day);
        return String.format("%ta", c);
    }

    private static String capitalize(String s) {
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }

    private static class Strings {

        static String daily = "daily";
        static String weekly = "weekly";
        static String monthly = "monthly";
        static String yearly = "yearly";

        static String days = "days";
        static String weeks = "weeks";
        static String months = "months";
        static String years = "years";

        static String every = "every";
        static String on = "on";
        static String until = "until";
        static String four = "for"; // "for" is a reserved word
        static String times = "times";
        static String time = "time";

        static String one = "one";
        static String first = "first";
        static String second = "second";
        static String third = "third";
        static String fourth = "fourth";
        static String last = "last";

        static void init(String language) {
            // TODO: Support different locales
            if (language.equals("es")) {
                daily = "diariamente";
                weekly = "semanal";
                monthly = "mensual";
                yearly = "anual";

                days = "días";
                weeks = "semanas";
                months = "meses";
                years = "años";

                every = "cada";
                on = "en";
                until = "hasta";
                four = "para";
                times = "veces";
                time = "vez";

                one = "una";
                first = "primero";
                second = "segundo";
                third = "tercero";
                fourth = "cuarto";
                last = "último";
            }
        }
    }

    public static class TextParseException extends Exception {
        TextParseException() {
            super();
        }

        TextParseException(String message) {
            super(message);
        }
    }
}
person Aaron DeLory    schedule 31.07.2017

В следующей версии библиотеки Recurrent будет функция deparse(). Это на питоне.

person snoopyjc    schedule 15.08.2020
comment
Он был выпущен! Функция называется формат(). - person snoopyjc; 13.09.2020