diff --git a/Source/Modules/LangModelRelated/LMInstantiator.swift b/Source/Modules/LangModelRelated/LMInstantiator.swift index a86c9551..38a9e019 100644 --- a/Source/Modules/LangModelRelated/LMInstantiator.swift +++ b/Source/Modules/LangModelRelated/LMInstantiator.swift @@ -205,6 +205,9 @@ extension vChewing { rawAllUnigrams += vChewing.LMInstantiator.lmSymbols.unigramsFor(key: key) } + // 新增與日期、時間、星期有關的單元圖資料 + rawAllUnigrams.append(contentsOf: queryDateTimeUnigrams(with: key)) + // 準備過濾清單。因為我們在 Swift 使用 NSOrderedSet,所以就不需要統計清單了。 var filteredPairs: Set = [] diff --git a/Source/Modules/LangModelRelated/LMInstantiator_DateTimeExtension.swift b/Source/Modules/LangModelRelated/LMInstantiator_DateTimeExtension.swift new file mode 100644 index 00000000..e6987ee6 --- /dev/null +++ b/Source/Modules/LangModelRelated/LMInstantiator_DateTimeExtension.swift @@ -0,0 +1,94 @@ +// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License). +// ==================== +// This code is released under the MIT license (SPDX-License-Identifier: MIT) +// ... with NTL restriction stating that: +// No trademark license is granted to use the trade names, trademarks, service +// marks, or product names of Contributor, except as required to fulfill notice +// requirements defined in MIT License. + +import Foundation + +// MARK: - 日期時間便捷輸入功能 + +extension vChewing.LMInstantiator { + func queryDateTimeUnigrams(with key: String = "") -> [Megrez.Unigram] { + if !["ㄖˋ-ㄑㄧ", "ㄖˋ-ㄑㄧˊ", "ㄕˊ-ㄐㄧㄢ", "ㄒㄧㄥ-ㄑㄧ", "ㄒㄧㄥ-ㄑㄧˊ"].contains(key) { return .init() } + var results = [Megrez.Unigram]() + let theLocale = Locale(identifier: "zh-Hant") + let currentDate = Date() + var delta = DateComponents() + let thisYear = Calendar.current.dateComponents([.year], from: currentDate).year ?? 2018 + delta.year = max(min(mgrPrefs.deltaOfCalendarYears, 0), thisYear * -1) + let currentDateShortened = Calendar.current.date(byAdding: delta, to: currentDate) + switch key { + case "ㄖˋ-ㄑㄧ", "ㄖˋ-ㄑㄧˊ": + let formatterDate1 = DateFormatter() + let formatterDate2 = DateFormatter() + formatterDate1.dateFormat = "yyyy-MM-dd" + formatterDate2.dateFormat = "yyyy年MM月dd日" + let date1 = formatterDate1.string(from: currentDate) + let date2 = formatterDate2.string(from: currentDate) + var date3 = ChineseConverter.convertArabicNumeralsToChinese(target: date2) + date3 = date3.replacingOccurrences(of: "年〇", with: "年") + date3 = date3.replacingOccurrences(of: "月〇", with: "月") + results.append(.init(keyValue: .init(key: key, value: date1), score: -94)) + results.append(.init(keyValue: .init(key: key, value: date2), score: -95)) + results.append(.init(keyValue: .init(key: key, value: date3), score: -96)) + if let currentDateShortened = currentDateShortened, delta.year != 0 { + var dateAlt1: String = formatterDate1.string(from: currentDateShortened) + dateAlt1.regReplace(pattern: #"^0+"#) + var dateAlt2: String = formatterDate2.string(from: currentDateShortened) + dateAlt2.regReplace(pattern: #"^0+"#) + var dateAlt3 = ChineseConverter.convertArabicNumeralsToChinese(target: dateAlt2) + dateAlt3 = dateAlt3.replacingOccurrences(of: "年〇", with: "年") + dateAlt3 = dateAlt3.replacingOccurrences(of: "月〇", with: "月") + results.append(.init(keyValue: .init(key: key, value: dateAlt1), score: -97)) + results.append(.init(keyValue: .init(key: key, value: dateAlt2), score: -98)) + results.append(.init(keyValue: .init(key: key, value: dateAlt3), score: -99)) + } + case "ㄕˊ-ㄐㄧㄢ": + let formatterTime1 = DateFormatter() + let formatterTime2 = DateFormatter() + let formatterTime3 = DateFormatter() + formatterTime1.dateFormat = "HH:mm" + formatterTime2.dateFormat = IME.currentInputMode == .imeModeCHS ? "HH点mm分" : "HH點mm分" + formatterTime3.dateFormat = IME.currentInputMode == .imeModeCHS ? "HH时mm分" : "HH時mm分" + let time1 = formatterTime1.string(from: currentDate) + let time2 = formatterTime2.string(from: currentDate) + let time3 = formatterTime3.string(from: currentDate) + results.append(.init(keyValue: .init(key: key, value: time1), score: -97)) + results.append(.init(keyValue: .init(key: key, value: time2), score: -98)) + results.append(.init(keyValue: .init(key: key, value: time3), score: -99)) + case "ㄒㄧㄥ-ㄑㄧ", "ㄒㄧㄥ-ㄑㄧˊ": + let formatterWeek1 = DateFormatter() + let formatterWeek2 = DateFormatter() + formatterWeek1.dateFormat = "EEEE" + formatterWeek2.dateFormat = "EE" + formatterWeek1.locale = theLocale + formatterWeek2.locale = theLocale + let week1 = formatterWeek1.string(from: currentDate) + let week2 = formatterWeek2.string(from: currentDate) + results.append(.init(keyValue: .init(key: key, value: week1), score: -98)) + results.append(.init(keyValue: .init(key: key, value: week2), score: -99)) + default: return .init() + } + return results + } +} + +// MARK: - String Extension + +extension String { + fileprivate mutating func regReplace(pattern: String, replaceWith: String = "") { + // Ref: https://stackoverflow.com/a/40993403/4162914 && https://stackoverflow.com/a/71291137/4162914 + do { + let regex = try NSRegularExpression( + pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines] + ) + let range = NSRange(startIndex..., in: self) + self = regex.stringByReplacingMatches( + in: self, options: [], range: range, withTemplate: replaceWith + ) + } catch { return } + } +} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 3b40eee5..80ecca8f 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 5B40730C281672610023DFFF /* lmAssociates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B407309281672610023DFFF /* lmAssociates.swift */; }; 5B40730D281672610023DFFF /* lmReplacements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B40730A281672610023DFFF /* lmReplacements.swift */; }; 5B54E743283A7D89001ECBDC /* lmCoreNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B54E742283A7D89001ECBDC /* lmCoreNS.swift */; }; + 5B5948CE289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift */; }; 5B5E535227EF261400C6AA1E /* IME.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5E535127EF261400C6AA1E /* IME.swift */; }; 5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */; }; 5B62A33227AE792F00A19448 /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */; }; @@ -222,6 +223,7 @@ 5B407309281672610023DFFF /* lmAssociates.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; lineEnding = 0; path = lmAssociates.swift; sourceTree = ""; usesTabs = 0; }; 5B40730A281672610023DFFF /* lmReplacements.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; lineEnding = 0; path = lmReplacements.swift; sourceTree = ""; usesTabs = 0; }; 5B54E742283A7D89001ECBDC /* lmCoreNS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = lmCoreNS.swift; sourceTree = ""; }; + 5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LMInstantiator_DateTimeExtension.swift; sourceTree = ""; }; 5B5E535127EF261400C6AA1E /* IME.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = IME.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputSourceHelper.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; @@ -513,6 +515,7 @@ 5B407308281672610023DFFF /* SubLMs */, 5B949BDA2816DDBC00D87B5D /* LMConsolidator.swift */, 5BD0113A28180D6100609769 /* LMInstantiator.swift */, + 5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift */, 5B3A87BB28597CDB0090E163 /* LMSymbolNode.swift */, 5BAEFACF28012565001F42C9 /* mgrLangModel.swift */, ); @@ -1185,6 +1188,7 @@ 5BA9FD4227FEF3C8002DE248 /* PreferencePane.swift in Sources */, 5BA0DF312817857D009E73BB /* lmUserOverride.swift in Sources */, 5BA9FD8B28006B41002DE248 /* VDKComboBox.swift in Sources */, + 5B5948CE289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift in Sources */, 5BA9FD4A27FEF3C9002DE248 /* PreferencesTabViewController.swift in Sources */, 5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */, 5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */,