using System.Text.RegularExpressions;
namespace Core.Parsers.EventOccurrence;
///
/// Parses time and location from combined strings.
/// Extracts time using regex, then uses everything after the time as the location.
///
public static class TimeLocationParser
{
// Shared time value pattern: matches either NOON or a time with AM/PM (e.g., "10:30 a.m.", "3 p.m.")
private static string TimeValuePattern => TimePatterns.TimeValue;
// Regex to match time ranges like "10:30 a.m. - 12:00 p.m." or "10:30 a.m. - NOON"
// Matches: time1 (optional dash time2/NOON), then location
// The time group captures the full time range (including " - NOON" if present)
// Note: Input is normalized via SanitizeInput, so only regular hyphens need to be handled
private static readonly Regex TimeLocationRegex = new(
$@"(?{TimeValuePattern}(?:\s*-\s*{TimeValuePattern})?)(?:\s+(?.+))?",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
// Pattern for cleaning time components from location text
// Matches optional dash, whitespace, time pattern, optional whitespace at start
// Handles: "- 12:15 p.m. ", "12:15 p.m. ", "- NOON ", "NOON ", etc.
private static readonly Regex TimeInLocationPattern = new(
$@"^(?:-\s*)?{TimeValuePattern}(?:\s+|$)",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
///
/// Parses time and location from the timeAndLocation string.
/// Extracts time using regex, then uses everything after the time as the location (after cleaning time fragments).
///
/// The combined time and location string.
/// Output parameter: the parsed time string.
/// Output parameter: the parsed location string.
public static void Parse(
string timeAndLocation,
out string time,
out string location)
{
// Extract time using regex
var timeLocationMatch = TimeLocationRegex.Match(timeAndLocation);
if (!timeLocationMatch.Success)
{
// If time regex doesn't match, use the whole string as time
time = timeAndLocation.Trim();
location = string.Empty;
return;
}
time = timeLocationMatch.Groups["Time"].Captures[0].Value.Trim();
var locationPart = timeLocationMatch.Groups["Location"].Success
? timeLocationMatch.Groups["Location"].Captures[0].Value.Trim()
: string.Empty;
// No location part found, which is valid (some events might not have locations)
if (string.IsNullOrWhiteSpace(locationPart))
{
location = string.Empty;
return;
}
// Clean location of any remaining time fragments
// (e.g., "– 12:15 p.m. Exhibit Hall C" -> "Exhibit Hall C")
location = CleanLocationText(locationPart);
}
///
/// Cleans location text by removing any remaining time components from the start.
/// Handles cases like "- 12:15 p.m. Exhibit Hall C" -> "Exhibit Hall C"
/// Note: Input is normalized, so only regular hyphens need to be handled.
///
public static string CleanLocationText(string locationText)
{
if (string.IsNullOrWhiteSpace(locationText))
return string.Empty;
// Remove time pattern from start, repeat until no more matches
string previous;
do
{
previous = locationText;
locationText = TimeInLocationPattern.Replace(locationText, "").Trim();
} while (locationText != previous && !string.IsNullOrWhiteSpace(locationText));
// If result is empty or only whitespace, return empty
return string.IsNullOrWhiteSpace(locationText) ? string.Empty : locationText;
}
}