diff --git a/CMakeLists.txt b/CMakeLists.txt index 914b588..76a213e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,9 @@ if (ENABLE_CLANG_TIDY) MESSAGE(STATUS "Found clang-tidy: ${CLANG_TIDY}") string(CONCAT CLANG_TIDY_CHECKS "-checks=-*," "clang-analyzer-*,bugprone-*,cert-*,readability-*," + "clang-diagnostic-*," + "cppcoreguidelines-explicit-virtual-functions," + "cppcoreguidelines-virtual-class-destructor," "-bugprone-easily-swappable-parameters," "-readability-const-return-type," "-readability-convert-member-functions-to-static," diff --git a/data/data.txt b/data/data.txt index ebc736b..cdaf33f 100644 --- a/data/data.txt +++ b/data/data.txt @@ -16764,6 +16764,15 @@ _punctuation_~ ~ 0.0 ㄇㄧㄥˊ-ㄊㄧㄝˋ 名帖 -7.56766981 ㄇㄧㄥˊ-ㄊㄧㄠˊ 名條 -6.56766981 ㄇㄧㄥˊ-ㄊㄧㄢ 明天 -4.08622719 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_SHORT -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_MEDIUM -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_MEDIUM_ROC -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_MEDIUM_CHINESE -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_MEDIUM_JAPANESE -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_WEEKDAY_SHORT -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_WEEKDAY -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW2_WEEKDAY -8 +ㄇㄧㄥˊ-ㄊㄧㄢ MACRO@DATE_TOMORROW_WEEKDAY_JAPANESE -8 ㄇㄧㄥˊ-ㄊㄧㄢ-ㄉㄜ˙ 明天的 -5.34470065 ㄇㄧㄥˊ-ㄊㄧㄢ-ㄕㄤˋ-ㄨˇ-ㄅㄚ-ㄕˊ 明天上午八時 -6.69148813 ㄇㄧㄥˊ-ㄊㄧㄢ-ㄖˋ-ㄑㄧˊ 明天日期 -8 @@ -16781,6 +16790,12 @@ _punctuation_~ ~ 0.0 ㄇㄧㄥˊ-ㄋㄧㄠˇ 鳴鳥 -6.56766981 ㄇㄧㄥˊ-ㄋㄧㄠˇ 名鳥 -7.56766981 ㄇㄧㄥˊ-ㄋㄧㄢˊ 明年 -4.10407541 +ㄇㄧㄥˊ-ㄋㄧㄢˊ MACRO@NEXT_YEAR_GANZHI -8 +ㄇㄧㄥˊ-ㄋㄧㄢˊ MACRO@NEXT_YEAR_CHINESE_ZODIAC -8 +ㄇㄧㄥˊ-ㄋㄧㄢˊ MACRO@NEXT_YEAR_PLAIN -8 +ㄇㄧㄥˊ-ㄋㄧㄢˊ MACRO@NEXT_YEAR_PLAIN_WITH_ERA -8 +ㄇㄧㄥˊ-ㄋㄧㄢˊ MACRO@NEXT_YEAR_ROC -8 +ㄇㄧㄥˊ-ㄋㄧㄢˊ MACRO@NEXT_YEAR_JAPANESE -8 ㄇㄧㄥˊ-ㄋㄧㄢˊ-ㄉㄜ˙ 明年的 -5.22522481 ㄇㄧㄥˊ-ㄋㄧㄢˊ-ㄍㄢ-ㄓ 明年干支 -8 ㄇㄧㄥˊ-ㄋㄧㄢˊ-ㄍㄢ-ㄓ MACRO@NEXT_YEAR_GANZHI -8 @@ -77397,6 +77412,15 @@ _punctuation_~ ~ 0.0 ㄐㄧㄣ-ㄊㄧㄝ 津貼 -4.75743730 ㄐㄧㄣ-ㄊㄧㄠˊ 金條 -5.88642858 ㄐㄧㄣ-ㄊㄧㄢ 今天 -3.28937361 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_SHORT -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_MEDIUM -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_MEDIUM_ROC -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_MEDIUM_CHINESE -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_MEDIUM_JAPANESE -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_WEEKDAY_SHORT -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_WEEKDAY -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY2_WEEKDAY -8 +ㄐㄧㄣ-ㄊㄧㄢ MACRO@DATE_TODAY_WEEKDAY_JAPANESE -8 ㄐㄧㄣ-ㄊㄧㄢ-ㄉㄜ˙ 今天的 -4.34181496 ㄐㄧㄣ-ㄊㄧㄢ-ㄋㄥˊ 今天能 -6.82182190 ㄐㄧㄣ-ㄊㄧㄢ-ㄏㄨㄟˋ 今天會 -5.67569387 @@ -77419,6 +77443,12 @@ _punctuation_~ ~ 0.0 ㄐㄧㄣ-ㄋㄧㄡˊ ♉ -8 ㄐㄧㄣ-ㄋㄧㄡˊ-ㄗㄨㄛˋ 金牛座 -5.60433796 ㄐㄧㄣ-ㄋㄧㄢˊ 今年 -3.57582376 +ㄐㄧㄣ-ㄋㄧㄢˊ MACRO@THIS_YEAR_GANZHI -8 +ㄐㄧㄣ-ㄋㄧㄢˊ MACRO@THIS_YEAR_CHINESE_ZODIAC -8 +ㄐㄧㄣ-ㄋㄧㄢˊ MACRO@THIS_YEAR_PLAIN -8 +ㄐㄧㄣ-ㄋㄧㄢˊ MACRO@THIS_YEAR_PLAIN_WITH_ERA -8 +ㄐㄧㄣ-ㄋㄧㄢˊ MACRO@THIS_YEAR_ROC -8 +ㄐㄧㄣ-ㄋㄧㄢˊ MACRO@THIS_YEAR_JAPANESE -8 ㄐㄧㄣ-ㄋㄧㄢˊ-ㄍㄢ-ㄓ 今年干支 -8 ㄐㄧㄣ-ㄋㄧㄢˊ-ㄍㄢ-ㄓ MACRO@THIS_YEAR_GANZHI -8 ㄐㄧㄣ-ㄋㄧㄢˊ-ㄕㄥ-ㄒㄧㄠˋ 今年生肖 -8 @@ -85980,6 +86010,12 @@ _punctuation_~ ~ 0.0 ㄑㄩˋ-ㄊㄢˊ 趣談 -6.56766981 ㄑㄩˋ-ㄋㄧˇ-ㄉㄜ˙ 去你的 -6.27775386 ㄑㄩˋ-ㄋㄧㄢˊ 去年 -3.80140572 +ㄑㄩˋ-ㄋㄧㄢˊ MACRO@LAST_YEAR_GANZHI -8 +ㄑㄩˋ-ㄋㄧㄢˊ MACRO@LAST_YEAR_CHINESE_ZODIAC -8 +ㄑㄩˋ-ㄋㄧㄢˊ MACRO@LAST_YEAR_PLAIN -8 +ㄑㄩˋ-ㄋㄧㄢˊ MACRO@LAST_YEAR_PLAIN_WITH_ERA -8 +ㄑㄩˋ-ㄋㄧㄢˊ MACRO@LAST_YEAR_ROC -8 +ㄑㄩˋ-ㄋㄧㄢˊ MACRO@LAST_YEAR_JAPANESE -8 ㄑㄩˋ-ㄋㄧㄢˊ-ㄉㄜ˙ 去年的 -5.08542540 ㄑㄩˋ-ㄋㄧㄢˊ-ㄉㄨˋ 去年度 -5.82182190 ㄑㄩˋ-ㄋㄧㄢˊ-ㄍㄢ-ㄓ 去年干支 -8 @@ -92041,6 +92077,8 @@ _punctuation_~ ~ 0.0 ㄒㄧㄢˋ-ㄖㄨˋ-ㄐㄧㄤ-ㄐㄩˊ 陷入僵局 -6.50194272 ㄒㄧㄢˋ-ㄖㄨˋ-ㄐㄩㄝˊ-ㄐㄧㄥˋ 陷入絕境 -7.28009397 ㄒㄧㄢˋ-ㄗㄞˋ 現在 -3.17490254 +ㄒㄧㄢˋ-ㄗㄞˋ MACRO@TIME_NOW_SHORT -8 +ㄒㄧㄢˋ-ㄗㄞˋ MACRO@TIME_NOW_MEDIUM -8 ㄒㄧㄢˋ-ㄗㄞˋ 陷在 -6.78951856 ㄒㄧㄢˋ-ㄗㄞˋ-ㄉㄜ˙ 現在的 -4.31803122 ㄒㄧㄢˋ-ㄗㄞˋ-ㄕˊ-ㄎㄜˋ 現在時刻 -8 @@ -112334,6 +112372,8 @@ _punctuation_~ ~ 0.0 ㄕˊ-ㄑㄧㄥ 石青 -7.26663982 ㄕˊ-ㄑㄧㄥˊ 實情 -5.46729927 ㄕˊ-ㄑㄩ 時區 -5.94442052 +ㄕˊ-ㄑㄩ MACRO@TIMEZONE_STANDARD -8 +ㄕˊ-ㄑㄩ MACRO@TIMEZONE_GENERIC_SHORT -8 ㄕˊ-ㄑㄩ 十區 -7.26663982 ㄕˊ-ㄑㄩˇ 拾取 -6.66457983 ㄕˊ-ㄑㄩˇ 十曲 -7.56766981 @@ -125754,6 +125794,15 @@ _punctuation_~ ~ 0.0 ㄗㄨㄛˊ 筰 -7.71145774 ㄗㄨㄛˊ 葃 -7.71145774 ㄗㄨㄛˊ-ㄊㄧㄢ 昨天 -3.71470212 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_SHORT -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_MEDIUM -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_MEDIUM_ROC -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_MEDIUM_CHINESE -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_MEDIUM_JAPANESE -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_WEEKDAY_SHORT -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_WEEKDAY -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY2_WEEKDAY -8 +ㄗㄨㄛˊ-ㄊㄧㄢ MACRO@DATE_YESTERDAY_WEEKDAY_JAPANESE -8 ㄗㄨㄛˊ-ㄊㄧㄢ-ㄉㄜ˙ 昨天的 -5.38248921 ㄗㄨㄛˊ-ㄊㄧㄢ-ㄒㄧㄚˋ-ㄨˇ 昨天下午 -5.36628012 ㄗㄨㄛˊ-ㄊㄧㄢ-ㄓㄨㄥ-ㄨˇ 昨天中午 -6.20091272 diff --git a/src/InputMacro.cpp b/src/InputMacro.cpp index ada925b..3253ae0 100644 --- a/src/InputMacro.cpp +++ b/src/InputMacro.cpp @@ -3,160 +3,474 @@ #include #include +#include #include +#include #include #include namespace McBopomofo { -class InputMacroDateTodayShort : public InputMacro { +std::string formatDate(std::string calendarName, int dayOffset, + icu::DateFormat::EStyle dateStyle); +std::string formatWithPattern(std::string calendarName, int yearOffset, int dateOffset, icu::UnicodeString pattern); +std::string formatTime(icu::DateFormat::EStyle timeStyle); +std::string formatTimeZone(icu::TimeZone::EDisplayType type); +int currentYear(); +std::string ganzhi(int year); +std::string chineseZodiac(int year); + +class InputMacroDate : public InputMacro { public: - std::string name() const { return "MACRO@DATE_TODAY_SHORT"; } - std::string replacement() const; + InputMacroDate(std::string macroName, std::string calendar, int offset, + icu::DateFormat::EStyle style) + : name_(macroName), + calendarName_(calendar), + dayOffset_(offset), + dateStyle_(style) {} + std::string name() const override { return name_; } + std::string replacement() const override { + return formatDate(calendarName_, dayOffset_, dateStyle_); + } + + private: + std::string name_; + std::string calendarName_; + int dayOffset_; + icu::DateFormat::EStyle dateStyle_; }; -class InputMacroDateTodayMedium : public InputMacro { +class InputMacroYear : public InputMacro { public: - std::string name() const { return "MACRO@DATE_TODAY_MEDIUM"; } - std::string replacement() const; + InputMacroYear(std::string macroName, std::string calendar, int offset, icu::UnicodeString pattern) + : name_(macroName), + calendarName_(calendar), + yearOffset_(offset), + pattern_(pattern) {} + std::string name() const override { return name_; } + std::string replacement() const override { + return formatWithPattern(calendarName_, yearOffset_, /*dateOffset*/ 0, pattern_) + "年"; + } + + private: + std::string name_; + std::string calendarName_; + int yearOffset_; + // ref: https://unicode-org.github.io/icu/userguide/format_parse/datetime/index#datetime-format-syntax + icu::UnicodeString pattern_; }; -class InputMacroDateTodayMediumRoc : public InputMacro { +class InputMacroDayOfTheWeek : public InputMacro { public: - std::string name() const { return "MACRO@DATE_TODAY_MEDIUM_ROC"; } - std::string replacement() const; + InputMacroDayOfTheWeek(std::string macroName, std::string calendar, int offset, icu::UnicodeString pattern) + : name_(macroName), + calendarName_(calendar), + dayOffset_(offset), + pattern_(pattern) {} + std::string name() const override { return name_; } + std::string replacement() const override { + return formatWithPattern(calendarName_, /*yearOffset*/ 0, dayOffset_, pattern_); + } + + private: + std::string name_; + std::string calendarName_; + int dayOffset_; + icu::UnicodeString pattern_; }; -class InputMacroDateTodayMediumChinese : public InputMacro { +class InputMacroDateTime : public InputMacro { public: - std::string name() const { return "MACRO@DATE_TODAY_MEDIUM_CHINESE"; } - std::string replacement() const; + InputMacroDateTime(std::string macroName, icu::DateFormat::EStyle style) + : name_(macroName), timeStyle_(style) {} + std::string name() const override { return name_; } + std::string replacement() const override { + return formatTime(timeStyle_); + } + + private: + std::string name_; + icu::DateFormat::EStyle timeStyle_; }; -class InputMacroDateTodayMediumJapanese : public InputMacro { +class InputMacroTimeZone : public InputMacro { public: - std::string name() const { return "MACRO@DATE_TODAY_MEDIUM_JAPANESE"; } - std::string replacement() const; + InputMacroTimeZone(std::string macroName, icu::TimeZone::EDisplayType type) + : name_(macroName), type_(type) {} + std::string name() const override { return name_; } + std::string replacement() const override { + return formatTimeZone(type_); + } + + private: + std::string name_; + icu::TimeZone::EDisplayType type_; }; -class InputMacroDateYesterdayShort : public InputMacro { + +// transform is a function that takes an int and returns a string +template +class InputMacroTransform : public InputMacro { public: - std::string name() const { return "MACRO@DATE_YESTERDAY_SHORT"; } - std::string replacement() const; + InputMacroTransform(std::string macroName, int yearOffset, transform t) + : name_(macroName), yearOffset_(yearOffset), t_(t) {} + std::string name() const override { return name_; } + std::string replacement() const override { + int year = currentYear(); + return t_(year + yearOffset_); + } + + private: + std::string name_; + int yearOffset_; + transform t_; }; -class InputMacroDateYesterdayMedium : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_YESTERDAY_MEDIUM"; } - std::string replacement() const; +// currying +class InputMacroGanZhi : public InputMacroTransform> { + public: + InputMacroGanZhi(std::string macroName, int yearOffset) + : InputMacroTransform(macroName, yearOffset, ganzhi) {} }; -class InputMacroDateYesterdayMediumRoc : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_YESTERDAY_MEDIUM_ROC"; } - std::string replacement() const; +class InputMacroZodiac : public InputMacroTransform> { + public: + InputMacroZodiac(std::string macroName, int yearOffset) + : InputMacroTransform(macroName, yearOffset, chineseZodiac) {} }; -class InputMacroDateYesterdayMediumChinese : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_YESTERDAY_MEDIUM_CHINESE"; } - std::string replacement() const; +class InputMacroDateTodayShort : public InputMacroDate { + public: + InputMacroDateTodayShort() + : InputMacroDate("MACRO@DATE_TODAY_SHORT", "", 0, + icu::DateFormat::EStyle::kShort) {} }; -class InputMacroDateYesterdayMediumJapanese : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_YESTERDAY_MEDIUM_JAPANESE"; } - std::string replacement() const; +class InputMacroDateTodayMedium : public InputMacroDate { + public: + InputMacroDateTodayMedium() + : InputMacroDate("MACRO@DATE_TODAY_MEDIUM", "", 0, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroDateTomorrowShort : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_TOMORROW_SHORT"; } - std::string replacement() const; +class InputMacroDateTodayMediumRoc : public InputMacroDate { + public: + InputMacroDateTodayMediumRoc() + : InputMacroDate("MACRO@DATE_TODAY_MEDIUM_ROC", "roc", 0, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroDateTomorrowMedium : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_TOMORROW_MEDIUM"; } - std::string replacement() const; +class InputMacroDateTodayMediumChinese : public InputMacroDate { + public: + InputMacroDateTodayMediumChinese() + : InputMacroDate("MACRO@DATE_TODAY_MEDIUM_CHINESE", "chinese", 0, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroDateTomorrowMediumRoc : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_TOMORROW_MEDIUM_ROC"; } - std::string replacement() const; +class InputMacroDateTodayMediumJapanese : public InputMacroDate { + public: + InputMacroDateTodayMediumJapanese() + : InputMacroDate("MACRO@DATE_TODAY_MEDIUM_JAPANESE", "japanese", 0, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroDateTomorrowMediumChinese : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_TOMORROW_MEDIUM_CHINESE"; } - std::string replacement() const; +class InputMacroDateYesterdayShort : public InputMacroDate { + public: + InputMacroDateYesterdayShort() + : InputMacroDate("MACRO@DATE_YESTERDAY_SHORT", "", -1, + icu::DateFormat::EStyle::kShort) {} }; -class InputMacroDateTomorrowMediumJapanese : public InputMacro { - public: - std::string name() const { return "MACRO@DATE_TOMORROW_MEDIUM_JAPANESE"; } - std::string replacement() const; +class InputMacroDateYesterdayMedium : public InputMacroDate { + public: + InputMacroDateYesterdayMedium() + : InputMacroDate("MACRO@DATE_YESTERDAY_MEDIUM", "", -1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroDateTimeNowShort : public InputMacro { - public: - std::string name() const { return "MACRO@TIME_NOW_SHORT"; } - std::string replacement() const; +class InputMacroDateYesterdayMediumRoc : public InputMacroDate { + public: + InputMacroDateYesterdayMediumRoc() + : InputMacroDate("MACRO@DATE_YESTERDAY_MEDIUM_ROC", "roc", -1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroDateTimeNowMedium : public InputMacro { - public: - std::string name() const { return "MACRO@TIME_NOW_MEDIUM"; } - std::string replacement() const; +class InputMacroDateYesterdayMediumChinese : public InputMacroDate { + public: + InputMacroDateYesterdayMediumChinese() + : InputMacroDate("MACRO@DATE_YESTERDAY_MEDIUM_CHINESE", "chinese", -1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroTimeZoneStandard : public InputMacro { - public: - std::string name() const { return "MACRO@TIMEZONE_STANDARD"; } - std::string replacement() const; +class InputMacroDateYesterdayMediumJapanese : public InputMacroDate { + public: + InputMacroDateYesterdayMediumJapanese() + : InputMacroDate("MACRO@DATE_YESTERDAY_MEDIUM_JAPANESE", "japanese", -1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroTimeZoneShortGeneric : public InputMacro { - public: - std::string name() const { return "MACRO@TIMEZONE_GENERIC_SHORT"; } - std::string replacement() const; +class InputMacroDateTomorrowShort : public InputMacroDate { + public: + InputMacroDateTomorrowShort() + : InputMacroDate("MACRO@DATE_TOMORROW_SHORT", "", 1, + icu::DateFormat::EStyle::kShort) {} }; -class InputMacroThisYearGanZhi : public InputMacro { - public: - std::string name() const { return "MACRO@THIS_YEAR_GANZHI"; } - std::string replacement() const; +class InputMacroDateTomorrowMedium : public InputMacroDate { + public: + InputMacroDateTomorrowMedium() + : InputMacroDate("MACRO@DATE_TOMORROW_MEDIUM", "", 1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroLastYearGanZhi : public InputMacro { - public: - std::string name() const { return "MACRO@LAST_YEAR_GANZHI"; } - std::string replacement() const; +class InputMacroDateTomorrowMediumRoc : public InputMacroDate { + public: + InputMacroDateTomorrowMediumRoc() + : InputMacroDate("MACRO@DATE_TOMORROW_MEDIUM_ROC", "roc", 1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroNextYearGanZhi : public InputMacro { - public: - std::string name() const { return "MACRO@NEXT_YEAR_GANZHI"; } - std::string replacement() const; +class InputMacroDateTomorrowMediumChinese : public InputMacroDate { + public: + InputMacroDateTomorrowMediumChinese() + : InputMacroDate("MACRO@DATE_TOMORROW_MEDIUM_CHINESE", "chinese", 1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroThisYearChineseZodiac : public InputMacro { - public: - std::string name() const { return "MACRO@THIS_YEAR_CHINESE_ZODIAC"; } - std::string replacement() const; +class InputMacroDateTomorrowMediumJapanese : public InputMacroDate { + public: + InputMacroDateTomorrowMediumJapanese() + : InputMacroDate("MACRO@DATE_TOMORROW_MEDIUM_JAPANESE", "japanese", 1, + icu::DateFormat::EStyle::kMedium) {} }; -class InputMacroLastYearChineseZodiac : public InputMacro { - public: - std::string name() const { return "MACRO@LAST_YEAR_CHINESE_ZODIAC"; } - std::string replacement() const; +class InputMacroThisYearPlain : public InputMacroYear { + public: + InputMacroThisYearPlain() + : InputMacroYear("MACRO@THIS_YEAR_PLAIN", "", 0, "y") {} }; -class InputMacroNextYearChineseZodiac : public InputMacro { - public: - std::string name() const { return "MACRO@NEXT_YEAR_CHINESE_ZODIAC"; } - std::string replacement() const; +class InputMacroThisYearPlainWithEra : public InputMacroYear { + public: + InputMacroThisYearPlainWithEra() + : InputMacroYear("MACRO@THIS_YEAR_PLAIN_WITH_ERA", "", 0, "Gy") {} +}; + +class InputMacroThisYearRoc : public InputMacroYear { + public: + InputMacroThisYearRoc() + : InputMacroYear("MACRO@THIS_YEAR_ROC", "roc", 0, "Gy") {} +}; + +class InputMacroThisYearJapanese : public InputMacroYear { + public: + InputMacroThisYearJapanese() + : InputMacroYear("MACRO@THIS_YEAR_JAPANESE", "japanese", 0, "Gy") {} +}; + +class InputMacroLastYearPlain : public InputMacroYear { + public: + InputMacroLastYearPlain() + : InputMacroYear("MACRO@LAST_YEAR_PLAIN", "", -1, "y") {} +}; + +class InputMacroLastYearPlainWithEra : public InputMacroYear { + public: + InputMacroLastYearPlainWithEra() + : InputMacroYear("MACRO@LAST_YEAR_PLAIN_WITH_ERA", "", -1, "Gy") {} +}; + +class InputMacroLastYearRoc : public InputMacroYear { + public: + InputMacroLastYearRoc() + : InputMacroYear("MACRO@LAST_YEAR_ROC", "roc", -1, "Gy") {} +}; + +class InputMacroLastYearJapanese : public InputMacroYear { + public: + InputMacroLastYearJapanese() + : InputMacroYear("MACRO@LAST_YEAR_JAPANESE", "japanese", -1, "Gy") {} +}; + +class InputMacroNextYearPlain : public InputMacroYear { + public: + InputMacroNextYearPlain() + : InputMacroYear("MACRO@NEXT_YEAR_PLAIN", "", 1, "y") {} +}; + +class InputMacroNextYearPlainWithEra : public InputMacroYear { + public: + InputMacroNextYearPlainWithEra() + : InputMacroYear("MACRO@NEXT_YEAR_PLAIN_WITH_ERA", "", 1, "Gy") {} +}; + +class InputMacroNextYearRoc : public InputMacroYear { + public: + InputMacroNextYearRoc() + : InputMacroYear("MACRO@NEXT_YEAR_ROC", "roc", 1, "Gy") {} +}; + +class InputMacroNextYearJapanese : public InputMacroYear { + public: + InputMacroNextYearJapanese() + : InputMacroYear("MACRO@NEXT_YEAR_JAPANESE", "japanese", 1, "Gy") {} +}; + +std::string convertWeekdayUnit(std::string& original) { + // s/星期/禮拜/ + std::string src = "星期"; + std::string dst = "禮拜"; + return original.replace(original.find(src), src.length(), dst); +} + +class InputMacroWeekdayTodayShort : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayTodayShort() + : InputMacroDayOfTheWeek("MACRO@DATE_TODAY_WEEKDAY_SHORT", "", 0, "E") {} +}; + +class InputMacroWeekdayToday : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayToday() + : InputMacroDayOfTheWeek("MACRO@DATE_TODAY_WEEKDAY", "", 0, "EEEE") {} +}; + +class InputMacroWeekdayToday2 : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayToday2() + : InputMacroDayOfTheWeek("MACRO@DATE_TODAY2_WEEKDAY", "", 0, "EEEE") {} + std::string replacement () const override { + std::string original(InputMacroDayOfTheWeek::replacement()); + return convertWeekdayUnit(original); + } +}; + +class InputMacroWeekdayTodayJapanese : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayTodayJapanese() + : InputMacroDayOfTheWeek("MACRO@DATE_TODAY_WEEKDAY_JAPANESE", "japanese", 0, "EEEE") {} +}; + +class InputMacroWeekdayYesterdayShort : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayYesterdayShort() + : InputMacroDayOfTheWeek("MACRO@DATE_YESTERDAY_WEEKDAY_SHORT", "", -1, "E") {} +}; + +class InputMacroWeekdayYesterday : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayYesterday() + : InputMacroDayOfTheWeek("MACRO@DATE_YESTERDAY_WEEKDAY", "", -1, "EEEE") {} +}; + +class InputMacroWeekdayYesterday2 : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayYesterday2() + : InputMacroDayOfTheWeek("MACRO@DATE_YESTERDAY2_WEEKDAY", "", -1, "EEEE") {} + std::string replacement () const override { + std::string original(InputMacroDayOfTheWeek::replacement()); + return convertWeekdayUnit(original); + } +}; + +class InputMacroWeekdayYesterdayJapanese : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayYesterdayJapanese() + : InputMacroDayOfTheWeek("MACRO@DATE_YESTERDAY_WEEKDAY_JAPANESE", "japanese", -1, "EEEE") {} +}; + +class InputMacroWeekdayTomorrowShort : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayTomorrowShort() + : InputMacroDayOfTheWeek("MACRO@DATE_TOMORROW_WEEKDAY_SHORT", "", 1, "E") {} +}; + +class InputMacroWeekdayTomorrow : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayTomorrow() + : InputMacroDayOfTheWeek("MACRO@DATE_TOMORROW_WEEKDAY", "", 1, "EEEE") {} +}; + +class InputMacroWeekdayTomorrow2 : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayTomorrow2() + : InputMacroDayOfTheWeek("MACRO@DATE_TOMORROW2_WEEKDAY", "", 1, "EEEE") {} + std::string replacement () const override { + std::string original(InputMacroDayOfTheWeek::replacement()); + return convertWeekdayUnit(original); + } +}; + +class InputMacroWeekdayTomorrowJapanese : public InputMacroDayOfTheWeek { + public: + InputMacroWeekdayTomorrowJapanese() + : InputMacroDayOfTheWeek("MACRO@DATE_TOMORROW_WEEKDAY_JAPANESE", "japanese", 1, "EEEE") {} +}; + +class InputMacroDateTimeNowShort : public InputMacroDateTime { + public: + InputMacroDateTimeNowShort() + : InputMacroDateTime("MACRO@TIME_NOW_SHORT", + icu::DateFormat::EStyle::kShort) {} +}; + +class InputMacroDateTimeNowMedium : public InputMacroDateTime { + public: + InputMacroDateTimeNowMedium() + : InputMacroDateTime("MACRO@TIME_NOW_MEDIUM", + icu::DateFormat::EStyle::kMedium) {} +}; + + +class InputMacroTimeZoneStandard : public InputMacroTimeZone { + public: + InputMacroTimeZoneStandard() + : InputMacroTimeZone("MACRO@TIMEZONE_STANDARD", + icu::TimeZone::EDisplayType::LONG_GENERIC) {} +}; + + +class InputMacroTimeZoneShortGeneric : public InputMacroTimeZone { + public: + InputMacroTimeZoneShortGeneric() + : InputMacroTimeZone("MACRO@TIMEZONE_GENERIC_SHORT", + icu::TimeZone::EDisplayType::SHORT_GENERIC) {} +}; + +class InputMacroThisYearGanZhi : public InputMacroGanZhi { + public: + InputMacroThisYearGanZhi() + : InputMacroGanZhi("MACRO@THIS_YEAR_GANZHI", 0) {} +}; + +class InputMacroLastYearGanZhi : public InputMacroGanZhi { + public: + InputMacroLastYearGanZhi() + : InputMacroGanZhi("MACRO@LAST_YEAR_GANZHI", -1) {} +}; + +class InputMacroNextYearGanZhi : public InputMacroGanZhi { + public: + InputMacroNextYearGanZhi() + : InputMacroGanZhi("MACRO@NEXT_YEAR_GANZHI", 1) {} +}; + +class InputMacroThisYearChineseZodiac : public InputMacroZodiac { + public: + InputMacroThisYearChineseZodiac() + : InputMacroZodiac("MACRO@THIS_YEAR_CHINESE_ZODIAC", 0) {} +}; + +class InputMacroLastYearChineseZodiac : public InputMacroZodiac { + public: + InputMacroLastYearChineseZodiac() + : InputMacroZodiac("MACRO@LAST_YEAR_CHINESE_ZODIAC", -1) {} +}; + +class InputMacroNextYearChineseZodiac : public InputMacroZodiac { + public: + InputMacroNextYearChineseZodiac() + : InputMacroZodiac("MACRO@NEXT_YEAR_CHINESE_ZODIAC", 1) {} }; static void AddMacro( @@ -171,6 +485,30 @@ InputMacroController::InputMacroController() { AddMacro(macros_, std::make_unique()); AddMacro(macros_, std::make_unique()); AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); + AddMacro(macros_, std::make_unique()); AddMacro(macros_, std::make_unique()); AddMacro(macros_, std::make_unique()); AddMacro(macros_, std::make_unique()); @@ -203,141 +541,82 @@ std::string InputMacroController::handle(std::string input) { return input; } -std::string formatDate(std::string calendarName, int DayOffset, - icu::DateFormat::EStyle dateStyle) { - UErrorCode status = U_ZERO_ERROR; - icu::TimeZone* timezone = icu::TimeZone::createDefault(); - std::string calendarNameBase = calendarName == "japanese" ? "ja_JP" : "zh_Hant_TW"; +icu::Locale createLocale(std::string calendarName) { + std::string calendarNameBase = + calendarName == "japanese" ? "ja_JP" : "zh_Hant_TW"; if (!calendarName.empty()) { calendarNameBase += "@calendar=" + calendarName; } - - const icu::Locale locale = - icu::Locale::createCanonical(calendarNameBase.c_str()); - icu::Calendar* calendar = - icu::Calendar::createInstance(timezone, locale, status); - calendar->setTime(icu::Calendar::getNow(), status); - calendar->add(icu::Calendar::DATE, DayOffset, status); - icu::DateFormat* dateFormatter = icu::DateFormat::createDateTimeInstance( - dateStyle, icu::DateFormat::EStyle::kNone, locale); - icu::UnicodeString formattedDate; - icu::FieldPosition fieldPosition; - dateFormatter->format(*calendar, formattedDate, fieldPosition); - std::string output; - formattedDate.toUTF8String(output); - delete calendar; - delete dateFormatter; - return output; + return icu::Locale::createCanonical(calendarNameBase.c_str()); } -std::string InputMacroDateTodayShort::replacement() const { - return formatDate("", 0, icu::DateFormat::EStyle::kShort); -} - -std::string InputMacroDateTodayMedium::replacement() const { - return formatDate("", 0, icu::DateFormat::EStyle::kMedium); -} - -std::string InputMacroDateTodayMediumRoc::replacement() const { - return formatDate("roc", 0, icu::DateFormat::EStyle::kMedium); -} - -std::string InputMacroDateTodayMediumChinese::replacement() const { - return formatDate("chinese", 0, icu::DateFormat::EStyle::kMedium); -} - -std::string InputMacroDateTodayMediumJapanese::replacement() const { - return formatDate("japanese", 0, icu::DateFormat::EStyle::kMedium); -} - -std::string InputMacroDateYesterdayShort::replacement() const { - return formatDate("", -1, icu::DateFormat::EStyle::kShort); -} - -std::string InputMacroDateYesterdayMedium::replacement() const { - return formatDate("", -1, icu::DateFormat::EStyle::kMedium); +std::unique_ptr createCalendar(icu::Locale locale) { + UErrorCode status = U_ZERO_ERROR; + icu::TimeZone* timezone = icu::TimeZone::createDefault(); + std::unique_ptr calendar(icu::Calendar::createInstance(timezone, locale, status)); + calendar->setTime(icu::Calendar::getNow(), status); + return calendar; } -std::string InputMacroDateYesterdayMediumRoc::replacement() const { - return formatDate("roc", -1, icu::DateFormat::EStyle::kMedium); -} +std::string formatWithStyle(std::string calendarName, int yearOffset, int dayOffset, + icu::DateFormat::EStyle dateStyle, + icu::DateFormat::EStyle timeStyle) { + UErrorCode status = U_ZERO_ERROR; -std::string InputMacroDateYesterdayMediumChinese::replacement() const { - return formatDate("chinese", -1, icu::DateFormat::EStyle::kMedium); -} + const icu::Locale locale = createLocale(calendarName); + std::unique_ptr calendar = createCalendar(locale); -std::string InputMacroDateYesterdayMediumJapanese::replacement() const { - return formatDate("japanese", -1, icu::DateFormat::EStyle::kMedium); -} + calendar->add(icu::Calendar::YEAR, yearOffset, status); + calendar->add(icu::Calendar::DATE, dayOffset, status); -std::string InputMacroDateTomorrowShort::replacement() const { - return formatDate("", 1, icu::DateFormat::EStyle::kShort); -} + std::unique_ptr dateFormatter(icu::DateFormat::createDateTimeInstance( + dateStyle, timeStyle, locale)); + icu::UnicodeString formattedDate; + icu::FieldPosition fieldPosition; + dateFormatter->format(*calendar, formattedDate, fieldPosition); -std::string InputMacroDateTomorrowMedium::replacement() const { - return formatDate("", 1, icu::DateFormat::EStyle::kMedium); + std::string output; + formattedDate.toUTF8String(output); + return output; } -std::string InputMacroDateTomorrowMediumRoc::replacement() const { - return formatDate("roc", 1, icu::DateFormat::EStyle::kMedium); -} +std::string formatWithPattern(std::string calendarName, int yearOffset, int dateOffset, icu::UnicodeString pattern) { + UErrorCode status = U_ZERO_ERROR; -std::string InputMacroDateTomorrowMediumChinese::replacement() const { - return formatDate("chinese", 1, icu::DateFormat::EStyle::kMedium); -} + const icu::Locale locale = createLocale(calendarName); + std::unique_ptr calendar = createCalendar(locale); -std::string InputMacroDateTomorrowMediumJapanese::replacement() const { - return formatDate("japanese", 1, icu::DateFormat::EStyle::kMedium); -} + calendar->add(icu::Calendar::YEAR, yearOffset, status); + calendar->add(icu::Calendar::DATE, dateOffset, status); -std::string formatTime(icu::DateFormat::EStyle timeStyle) { - UErrorCode status = U_ZERO_ERROR; - icu::TimeZone* timezone = icu::TimeZone::createDefault(); - std::string calendarNameBase = "zh_Hant_TW"; - const icu::Locale locale = - icu::Locale::createCanonical(calendarNameBase.c_str()); - icu::Calendar* calendar = - icu::Calendar::createInstance(timezone, locale, status); - calendar->setTime(icu::Calendar::getNow(), status); - icu::DateFormat* dateFormatter = icu::DateFormat::createDateTimeInstance( - icu::DateFormat::EStyle::kNone, timeStyle, locale); + icu::SimpleDateFormat dateFormatter(pattern, locale, status); icu::UnicodeString formattedDate; - icu::FieldPosition fieldPosition; - dateFormatter->format(*calendar, formattedDate, fieldPosition); + dateFormatter.format(calendar->getTime(status), formattedDate, status); + std::string output; formattedDate.toUTF8String(output); - delete calendar; - delete dateFormatter; return output; } -std::string InputMacroDateTimeNowShort::replacement() const { - return formatTime(icu::DateFormat::EStyle::kShort); +std::string formatDate(std::string calendarName, int dayOffset, + icu::DateFormat::EStyle dateStyle) { + return formatWithStyle(calendarName, /*yearOffset*/ 0, dayOffset, dateStyle, /*timeStyle*/ icu::DateFormat::EStyle::kNone); } -std::string InputMacroDateTimeNowMedium::replacement() const { - return formatTime(icu::DateFormat::EStyle::kMedium); +std::string formatTime(icu::DateFormat::EStyle timeStyle) { + return formatWithStyle(/*calendarName*/ "", /*yearOffset*/ 0, /*dayOffset*/ 0, /*dateStyle*/ icu::DateFormat::EStyle::kNone, timeStyle); } std::string formatTimeZone(icu::TimeZone::EDisplayType type) { - icu::TimeZone* timezone = icu::TimeZone::createDefault(); + std::unique_ptr timezone(icu::TimeZone::createDefault()); const icu::Locale locale = icu::Locale::createCanonical("zh_Hant_TW"); icu::UnicodeString formatted; timezone->getDisplayName(false, type, locale, formatted); std::string output; formatted.toUTF8String(output); - delete timezone; return output; } -std::string InputMacroTimeZoneStandard::replacement() const { - return formatTimeZone(icu::TimeZone::EDisplayType::LONG_GENERIC); -} - -std::string InputMacroTimeZoneShortGeneric::replacement() const { - return formatTimeZone(icu::TimeZone::EDisplayType::SHORT_GENERIC); -} - int currentYear() { UErrorCode status = U_ZERO_ERROR; icu::GregorianCalendar calendar(icu::TimeZone::createDefault(), status); @@ -354,15 +633,16 @@ int getYearBase(int year) { } return (year - 3) % 60; } +// NOLINTEND(readability-magic-numbers) std::string ganzhi(int year) { const std::vector gan( {"癸", "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬"}); const std::vector zhi( {"亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌"}); - int base = getYearBase(year); - int ganIndex = base % 10; - int zhiIndex = base % 12; + size_t base = static_cast(getYearBase(year)); + size_t ganIndex = base % gan.size(); + size_t zhiIndex = base % zhi.size(); return gan[ganIndex] + zhi[zhiIndex] + "年"; } @@ -371,41 +651,10 @@ std::string chineseZodiac(int year) { {"水", "木", "木", "火", "火", "土", "土", "金", "金", "水"}); const std::vector zhi( {"豬", "鼠", "牛", "虎", "兔", "龍", "蛇", "馬", "羊", "猴", "雞", "狗"}); - int base = getYearBase(year); - int ganIndex = base % 10; - int zhiIndex = base % 12; + size_t base = static_cast(getYearBase(year)); + size_t ganIndex = base % gan.size(); + size_t zhiIndex = base % zhi.size(); return gan[ganIndex] + zhi[zhiIndex] + "年"; } -// NOLINTEND(readability-magic-numbers) - -std::string InputMacroThisYearGanZhi::replacement() const { - int year = currentYear(); - return ganzhi(year); -} - -std::string InputMacroLastYearGanZhi::replacement() const { - int year = currentYear(); - return ganzhi(year - 1); -} - -std::string InputMacroNextYearGanZhi::replacement() const { - int year = currentYear(); - return ganzhi(year + 1); -} - -std::string InputMacroThisYearChineseZodiac::replacement() const { - int year = currentYear(); - return chineseZodiac(year); -} - -std::string InputMacroLastYearChineseZodiac::replacement() const { - int year = currentYear(); - return chineseZodiac(year - 1); -} - -std::string InputMacroNextYearChineseZodiac::replacement() const { - int year = currentYear(); - return chineseZodiac(year + 1); -} } // namespace McBopomofo diff --git a/src/InputMacro.h b/src/InputMacro.h index 7215f85..21ea12b 100644 --- a/src/InputMacro.h +++ b/src/InputMacro.h @@ -1,5 +1,5 @@ -#ifndef INPUTMACRO -#define INPUTMACRO +#ifndef SRC_INPUTMACRO_H_ +#define SRC_INPUTMACRO_H_ #include #include @@ -8,6 +8,8 @@ namespace McBopomofo { class InputMacro { public: + virtual ~InputMacro() = default; + virtual std::string name() const = 0; virtual std::string replacement() const = 0; }; @@ -24,4 +26,4 @@ class InputMacroController { } // namespace McBopomofo -#endif /* INPUTMACRO */ +#endif /* SRC_INPUTMACRO_H_ */