Skip to content

Instantly share code, notes, and snippets.

@idianal
Created April 22, 2022 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save idianal/9d5d6bec631c6c3abc590c2290e48b09 to your computer and use it in GitHub Desktop.
Save idianal/9d5d6bec631c6c3abc590c2290e48b09 to your computer and use it in GitHub Desktop.
A simplistic date range parser class in C#
class DateRangeParser
{
#region Global variables
private string[] _wordBankSplitParams = new string[] { " ", "and" };
private List<string> _monthList = new List<string>()
{
"January",
"Feburary",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
#endregion
public DateRangeParser() {}
/// <summary>
/// Parses a date range string and returns the start date and end date
/// Sample expected date range string format:
/// - 19 November - 31 December 2016
/// - 07 December 2016
/// - 12 and 13 December 2016
/// - 14 December 2016
/// - 22 December 2016
/// - 7 December 2016
/// - 01 - 31 January 2017
/// </summary>
/// <param name="dateRangeString">String to parse</param>
/// <returns>List containing start date and end date</returns>
public List<DateTime> parseDateRangeString(string dateRangeString)
{
List<DateTime> parsedDates = new List<DateTime>();
try
{
// Generate word bank and proximity table
// - Word bank is an array of WordBankObjects found in the input string.
// - Proximity table is a two-dimensional array. For each word (the subject) in the word bank,
// an array of integers exists indicating the distance of each element to the subject.
string[] wordBankArray = dateRangeString.Split(_wordBankSplitParams, StringSplitOptions.RemoveEmptyEntries);
List<WordBankObject> wordBankObjList = GenerateWordBank(dateRangeString, wordBankArray);
List<List<int>> proximityTable = GenerateProximityTable(wordBankObjList);
List<List<WordBankObject>> rankedWordBankObjTable = GenerateRankedWordBankObjTable(proximityTable, wordBankObjList);
#region Use word bank to find closest year and month
for (int i = 0; i < wordBankObjList.Count; i++)
{
if (wordBankObjList[i].Type == WordBankObjectType.Date)
{
bool foundYear = false;
bool foundMonth = false;
string closestYearString = string.Empty;
string closestMonthString = string.Empty;
for (int j = 0; j < rankedWordBankObjTable[i].Count; j++)
{
if (rankedWordBankObjTable[i][j].Type == WordBankObjectType.Year && foundYear == false)
{
closestYearString = rankedWordBankObjTable[i][j].Word;
foundYear = true;
}
else if (rankedWordBankObjTable[i][j].Type == WordBankObjectType.Month && foundMonth == false)
{
closestMonthString = rankedWordBankObjTable[i][j].Word;
foundMonth = true;
}
if (foundYear && foundMonth)
{
string dateStringtoParse = String.Join(" ", new[] { wordBankObjList[i].Word, closestMonthString, closestYearString });
DateTime parsedDate;
DateTime.TryParse(dateStringtoParse, out parsedDate);
parsedDates.Add(parsedDate);
foundMonth = false;
foundYear = false;
break;
}
}
}
#endregion
}
}
catch (Exception ex)
{
LogEvent(TraceLevel.Error, "Error in parsing date range from Scheduled Outages table", ex);
}
return parsedDates;
}
/// <summary>
/// Generate a ranked word bank table
/// </summary>
/// <param name="proximityTable"></param>
/// <param name="wordBankObjList"></param>
/// <returns>Ranked word bank table</returns>
private List<List<WordBankObject>> GenerateRankedWordBankObjTable(List<List<int>> proximityTable, List<WordBankObject> wordBankObjList)
{
List<List<WordBankObject>> rankedWordBankObjTable = new List<List<WordBankObject>>();
foreach (var proximityColumn in proximityTable)
{
List<WordBankObject> rankedWordBankObjList = new List<WordBankObject>();
for (int i = 0; i <= proximityColumn.Max(); i++)
{
for (int j = 0; j < proximityColumn.Count; j++)
{
if (proximityColumn[j] == i)
{
rankedWordBankObjList.Add(wordBankObjList[j]);
}
}
}
rankedWordBankObjTable.Add(rankedWordBankObjList);
}
return rankedWordBankObjTable;
}
/// <summary>
/// Generate a proximity table
/// - Proximity table is a two-dimensional array. For each word (the subject) in the word bank,
/// an array of integers exists indicating the distance of each element to the subject.
/// </summary>
/// <param name="wordBankObjList"></param>
/// <returns>Proximity table</returns>
private List<List<int>> GenerateProximityTable(List<WordBankObject> wordBankObjList)
{
List<List<int>> proximityTable = new List<List<int>>();
for (int i = 0; i < wordBankObjList.Count(); i++)
{
List<int> proximityColumn = new List<int>();
for (int j = 0; j < wordBankObjList.Count(); j++)
{
proximityColumn.Add(Math.Abs(wordBankObjList[i].Index - wordBankObjList[j].Index));
}
proximityTable.Add(proximityColumn);
}
return proximityTable;
}
/// <summary>
/// Generate a word bank
/// - Word bank is an array of WordBankObjects found in the input string.
/// </summary>
/// <param name="dateRangeString"></param>
/// <param name="wordBankArray"></param>
/// <returns>Word bank</returns>
private List<WordBankObject> GenerateWordBank(string dateRangeString, string[] wordBankArray)
{
List<WordBankObject> wordBankObjList = new List<WordBankObject>();
try
{
for (int i = 0; i < wordBankArray.Count(); i++)
{
string word = wordBankArray[i];
int wordInt;
WordBankObject wordBankObj;
if (Int32.TryParse(word, out wordInt))
{
switch (word.Length)
{
case 1:
case 2:
wordBankObj = new WordBankObject(word, WordBankObjectType.Date, i);
break;
case 4:
wordBankObj = new WordBankObject(word, WordBankObjectType.Year, i);
break;
default:
Exception ex = new Exception("Failed to parse word " + word + " from " + dateRangeString + " because of unknown type");
throw ex;
}
}
else
{
if (_monthList.Contains(word))
{
wordBankObj = new WordBankObject(word, WordBankObjectType.Month, i);
}
else if (word == "-")
{
wordBankObj = new WordBankObject(word, WordBankObjectType.Other, i);
}
else
{
Exception ex = new Exception("Failed to parse word " + word + " from " + dateRangeString + " because of unknown type");
throw ex;
}
}
wordBankObjList.Add(wordBankObj);
}
}
catch (Exception ex)
{
LogEvent(TraceLevel.Error, "Error in generating word bank", ex);
}
return wordBankObjList;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment