Fix NL parser: fuzzy tomorrow matching + relative date offsets

Handles tommorow/tomorow/tomarrow misspellings. Adds "in N days",
"in N weeks", and "next week" recognition with numeric and word forms.
This commit is contained in:
kutesir
2026-05-29 10:23:50 +03:00
parent dc99a3f1f0
commit bc55d27f45

View File

@@ -764,7 +764,7 @@ struct NLTaskParser {
// Day keywords
let dayTable: [(String, Int)] = [
("\\btoday\\b", 0),
("\\btomorrow\\b", 1),
("\\btom+[ao]r+ow\\b", 1),
("\\bmon(day)?\\b", daysUntil(2)),
("\\btue(sday)?\\b", daysUntil(3)),
("\\bwed(nesday)?\\b", daysUntil(4)),
@@ -773,11 +773,20 @@ struct NLTaskParser {
("\\bsat(urday)?\\b", daysUntil(7)),
("\\bsun(day)?\\b", daysUntil(1)),
]
for (pat, offset) in dayTable {
if let r = match(pat, in: lower) {
let d = cal.date(byAdding: .day, value: offset, to: Date()) ?? Date()
comps = cal.dateComponents([.year, .month, .day], from: d)
rawRanges.append(r); foundDay = true; break
// Relative offsets ("in N days", "next week")
if let (r, offset) = parseRelativeOffset(in: lower) {
let d = cal.date(byAdding: .day, value: offset, to: Date()) ?? Date()
comps = cal.dateComponents([.year, .month, .day], from: d)
rawRanges.append(r); foundDay = true
}
if !foundDay {
for (pat, offset) in dayTable {
if let r = match(pat, in: lower) {
let d = cal.date(byAdding: .day, value: offset, to: Date()) ?? Date()
comps = cal.dateComponents([.year, .month, .day], from: d)
rawRanges.append(r); foundDay = true; break
}
}
}
@@ -814,6 +823,22 @@ struct NLTaskParser {
.replacingOccurrences(of: " ", with: " ")
}
private static func parseRelativeOffset(in text: String) -> (NSRange, Int)? {
let wordNums = ["a": 1, "an": 1, "one": 1, "two": 2, "three": 3, "four": 4,
"five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10]
if let r = match("\\bnext\\s+week\\b", in: text) { return (r, 7) }
for (unit, mult) in [("days?", 1), ("weeks?", 7)] {
let pat = "\\bin\\s+(\\d+|a|an|one|two|three|four|five|six|seven|eight|nine|ten)\\s+\(unit)\\b"
guard let rx = try? NSRegularExpression(pattern: pat),
let m = rx.firstMatch(in: text, range: NSRange(text.startIndex..., in: text)),
m.numberOfRanges >= 2,
let nr = Range(m.range(at: 1), in: text) else { continue }
let ns = String(text[nr])
return (m.range, (Int(ns) ?? wordNums[ns] ?? 1) * mult)
}
return nil
}
private static func daysUntil(_ target: Int) -> Int {
let today = Calendar.current.component(.weekday, from: Date())
let d = target - today