Files
chapter-organizer/Core/Parsers/EventOccurrenceParser.cs
T
2025-08-01 14:10:44 -04:00

184 lines
4.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Text.RegularExpressions;
using Core.Entities;
using FuzzySharp;
namespace Core.Parsers;
public class EventOccurrenceParser
{
private FileSystemInfo _txtFile;
private ICollection<CompetitiveEvent> _events;
public EventOccurrenceParser(FileSystemInfo txtFile, ICollection<CompetitiveEvent> events)
{
_events = events;
_txtFile = txtFile;
}
private Regex _re =
new (
@"" + //
@"(?<Name>^[^#].*)\s" +
@"(?<Month>February|March|April|May|June|July)\s" +
@"(?<DayOfMonth>\d{1,2});?\s" +
@"(?<TimeAndLocation>.*)"
);
private readonly Regex _timeRe = new(@"(?<Hour>\d{1,2}):?(?<Minute>\d{2})?\s?(?<APM>(?:a|p)\.?m\.?)");
private readonly Regex _timeLocationRegex = new(@"(?<Time>.*(?>[AaPp]\.?[Mm]\.?))(?<Location>[\s\t].*)?");
public IDictionary<CompetitiveEvent, List<EventOccurrence>> Parse()
{
var occurrences = new Dictionary<CompetitiveEvent, List<EventOccurrence>>();
CompetitiveEvent currentEvent = null;
var lines = File.ReadLines(_txtFile.FullName);
foreach (var line in lines)
{
var match = _re.Match(line);
if (!match.Success)
{
if (line.Contains("MS"))
{
var evt =
(from e in _events
let rat = Fuzz.Ratio(e.Name, line.Trim())
where rat > 50
orderby rat descending
select e).FirstOrDefault();
if (evt == null)
continue;
currentEvent = evt;
continue;
}
if (line == "General Schedule")
{
currentEvent = CompetitiveEvent.GeneralSchedule;
continue;
}
if (line == "Voting Delegates")
{
currentEvent = CompetitiveEvent.VotingDelegates;
continue;
}
continue;
}
if (currentEvent == null)
continue;
var occurrenceName = match.Groups["Name"].Captures[0].Value;
var month = match.Groups["Month"].Captures[0].Value;
var dayOfMonth = match.Groups["DayOfMonth"].Captures[0].Value;
var timeAndLocation = match.Groups["TimeAndLocation"].Captures[0].Value;
occurrenceName = Regex.Replace(occurrenceName,
@"(?<Weekday>Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday),\s?$", "").Trim();
timeAndLocation = SanitizeInput(timeAndLocation);
var timeAndLocationMatch = _timeLocationRegex.Match(timeAndLocation);
var time = timeAndLocation;
var location = string.Empty;
if (timeAndLocationMatch.Success)
{
time= timeAndLocationMatch.Groups["Time"].Captures[0].Value;
if (timeAndLocationMatch.Groups["Location"].Success)
location = timeAndLocationMatch.Groups["Location"].Captures[0].Value;
}
var startDate = ParseDate(month, dayOfMonth, DateTime.Now.Year);
var startTime = ParseStartTime(time);
var t = new DateTime(startDate, startTime);
var eventOccurrence = new EventOccurrence
{
Name = occurrenceName, StartTime = t, Time = $"{time}", Date = $"{month} {dayOfMonth}",
Location = location
};
if (!occurrences.ContainsKey(currentEvent))
occurrences.Add(currentEvent, []);
occurrences[currentEvent].Add(eventOccurrence);
}
return occurrences;
}
private string SanitizeInput(string input)
{
input = input.Replace("", "-");
input = input.Replace("—", "-");
return input;
}
private DateOnly ParseDate(string month, string dayOfMonth, int year)
{
int monthNum = 1;
switch (month)
{
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;
}
var day = int.Parse(dayOfMonth);
return new DateOnly(year, monthNum, day); ;
}
private TimeOnly ParseStartTime(string time)
{
int hour = 0;
int minute = 0;
// get the part of the time before a timespan
if (time.Contains(" - "))
{
time = time[..time.IndexOf(" - ", StringComparison.Ordinal)];
}
if (time == "NOON")
hour = 12;
else
{
var timeMatch = _timeRe.Match(time.ToLower());
if (timeMatch.Success)
{
hour = int.Parse(timeMatch.Groups["Hour"].Captures[0].Value);
if (timeMatch.Groups["Minute"].Success)
{
minute = int.Parse(timeMatch.Groups["Minute"].Captures[0].Value);
}
if (timeMatch.Groups["APM"].Captures[0].Value is "p.m." or "pm" && hour < 12)
hour += 12;
}
}
return new TimeOnly(hour, minute, 0);
}
}