Add Sprache package and enhance event occurrence parsing with new grammar rules

This commit is contained in:
2026-01-08 08:23:31 -05:00
parent 5fdd5fadba
commit f32ce649cd
5 changed files with 373 additions and 32 deletions
+57 -32
View File
@@ -31,7 +31,7 @@ public class EventOccurrenceParser
new (
@"" + //
@"(?<Name>^[^#].*)\s" +
@"(?<Month>February|March|April|May|June|July)\s" +
@"(?<Month>January|February|March|April|May|June|July|August|September|October|November|December)\s" +
@"(?<DayOfMonth>\d{1,2});?\s" +
@"(?<TimeAndLocation>.*)"
);
@@ -63,14 +63,50 @@ public class EventOccurrenceParser
if (string.IsNullOrWhiteSpace(trimmedLine))
continue;
// Skip comment lines (starting with "#")
if (trimmedLine.StartsWith("#", StringComparison.Ordinal))
// Skip comment lines (starting with "#") - use grammar parser
if (EventOccurrenceGrammar.IsCommentLine(trimmedLine))
continue;
var match = _re.Match(trimmedLine);
if (!match.Success)
{
if (trimmedLine.Contains("MS"))
// Try to parse section header using grammar parser
var sectionHeader = EventOccurrenceGrammar.TryParseSectionHeader(trimmedLine);
if (sectionHeader.HasValue)
{
var (eventNamePart, schoolLevel) = sectionHeader.Value;
// Use fuzzy matching to find the best matching event definition
var evt =
(from e in _events
let rat = Fuzz.Ratio(e.Name, eventNamePart)
where rat > 50
orderby rat descending
select e).FirstOrDefault();
if (evt == null)
{
issues.Add(new ParsingIssue
{
LineNumber = index,
LineContent = trimmedLine,
IssueType = ParsingIssueType.UnmatchedLine,
Message = $"Section header '{eventNamePart} {schoolLevel}' found but no matching event definition (best match ratio: {Fuzz.Ratio(eventNamePart, _events.FirstOrDefault()?.Name ?? "")})"
});
continue;
}
currentEventDefinition = evt;
continue;
}
// Check for General Schedule/Session using grammar parser
if (EventOccurrenceGrammar.IsGeneralSchedule(trimmedLine))
{
currentEventDefinition = EventDefinition.GeneralSchedule;
continue;
}
// Also check for simple "MS" or "HS" in line (backward compatibility)
if (trimmedLine.Contains("MS") || trimmedLine.Contains("HS"))
{
var evt =
(from e in _events
@@ -85,18 +121,13 @@ public class EventOccurrenceParser
LineNumber = index,
LineContent = trimmedLine,
IssueType = ParsingIssueType.UnmatchedLine,
Message = $"Section header with 'MS' found but no matching event definition (best match ratio: {Fuzz.Ratio(trimmedLine, _events.FirstOrDefault()?.Name ?? "")})"
Message = $"Section header with 'MS' or 'HS' found but no matching event definition (best match ratio: {Fuzz.Ratio(trimmedLine, _events.FirstOrDefault()?.Name ?? "")})"
});
continue;
}
currentEventDefinition = evt;
continue;
}
if (trimmedLine == "General Schedule" || trimmedLine == "General Session")
{
currentEventDefinition = EventDefinition.GeneralSchedule;
continue;
}
// Skip continuation lines (lines that look like they're continuing from previous line)
// These are typically lines that:
@@ -280,31 +311,25 @@ public class EventOccurrenceParser
private DateOnly ParseDate(string month, string dayOfMonth, int year)
{
int monthNum = 1;
switch (month)
int monthNum = month.ToLower() switch
{
case "February":
monthNum = 2;
break;
case "March":
monthNum = 3;
break;
case "April":
monthNum = 4;
break;
case "May":
monthNum = 5;
break;
case "June":
monthNum = 6;
break;
case "July":
monthNum = 7;
break;
}
"january" => 1,
"february" => 2,
"march" => 3,
"april" => 4,
"may" => 5,
"june" => 6,
"july" => 7,
"august" => 8,
"september" => 9,
"october" => 10,
"november" => 11,
"december" => 12,
_ => throw new ArgumentException($"Invalid month: {month}", nameof(month))
};
var day = int.Parse(dayOfMonth);
return new DateOnly(year, monthNum, day); ;
return new DateOnly(year, monthNum, day);
}
/// <summary>