簡體   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