繁体   English   中英

RRULE 到人类可读的文本

[英]RRULE to human readable text

我想从 RRULE 字符串( RFC2445 )生成人类可读的文本(自然语言)。 我用谷歌搜索过,我发现只有一个 JavaScript 库( rrule.js )可以生成这样的文本。 但是我在 Android (Java) 中需要这个功能。

有没有像这样用 Java 编写的库? 如果没有,我听说过一些 Java 中的 JavaScript 引擎(例如 Rhino)但我非常担心我的 Android 应用程序的性能,因为看起来这个引擎有点重。

您可以编写自己的类来为您做这件事,也可以使用我写的这个类,而不是用不必要的 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);
        }
    }
}

在里面使用WebViewrrule.js来获取结果。 请参阅此答案: 如何从 Android 调用 javascript?

下一个版本的Recurrent库将有一个 deparse() 函数。 它在python中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM