using System.Collections.Generic;
using System.Globalization;
using System.Collections;
using CSharpFunctionalExtensions;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Diagnostics;
public static void Main()
var culture = new CultureInfo("en-US");
Console.WriteLine($"After setting, CultureInfo is {culture.Name.ToString()}");
Console.WriteLine($"After setting, CultureInfo DisplayName is {culture.DisplayName}");
Console.WriteLine($"After setting, CultureInfo NativeName is {culture.NativeName}");
Console.WriteLine($"The current culture IsNeutralCulture? {culture.IsNeutralCulture}");
Console.WriteLine("------------------------------------------------------------------------------------");
CultureInfo.CurrentCulture = culture;
CanCreate_DocNameElementsMount();
public static void CanCreate_DocNameElementsMount()
var nameToParse = "US abdominal-cisto hepático_5f9a739a-0b2e-4fcc-9228-81035e6e50ea da internação de 2803 até 03062022 - 23122022 v3.docx";
var docElements = new List<ElementDescription>();
var elementGuid = InNameGUID.CreateInstance(nameToParse, DocNamePart.Middle);
docElements.Add(ElementDescription.CreateInstance(elementGuid, DocNamePart.Middle, ElementRelativePosition.First, -1));
nameToParse = nameToParse.Replace(elementGuid.GUID, string.Empty);
var elementVer = VersionInSentence.CreateInstance(nameToParse);
docElements.Add(ElementDescription.CreateInstance(elementVer, DocNamePart.Last, ElementRelativePosition.First, -1));
nameToParse = nameToParse.Replace(elementVer.Version, string.Empty);
var cultureInfo = new CultureInfo("pt-BR");
var elementInt = IntervalInSentence.CreateInstance(nameToParse , cultureInfo);
docElements.Add(ElementDescription.CreateInstance(elementInt, DocNamePart.Middle, ElementRelativePosition.Last, -1));
nameToParse = nameToParse.Replace(elementInt.Interval.Value, string.Empty);
var elementDate = DateInSentence.CreateInstance(nameToParse , cultureInfo, null);
docElements.Add(ElementDescription.CreateInstance(elementDate, DocNamePart.Last, ElementRelativePosition.First, -1));
foreach (var docElement in docElements)
Console.WriteLine(docElement);
Console.WriteLine("------------------------------------------------------------------------------------");
[Description("mês/meses")]
[Description("dd/MM/yyyy HH:mm:ss")]
[Description("MM/dd/yyyy HH:mm:ss")]
[Description("yyyyMMddHHmmss")]
[Description("yyyy-MM-dd'T'HH:mm:ss.fffffff'Z'")]
public enum CertaintyAboutElement
public enum ElementRelativePosition
public enum WhichElementItIs
public enum TypeOfElement
public interface IElementType : IComparable
public class BaseElement : ValueObject
public int StartIndex { get; set; } = -1;
public string ConnectorBefore { get; set; } = string.Empty;
public string OriginalText { get; private protected set; } = string.Empty;
public Result<string> ElementValue { get; set; } = Result.Failure<string>("No value");
#region Overrides of ValueObject
protected override IEnumerable<IComparable> GetEqualityComponents()
yield return ConnectorBefore;
yield return OriginalText;
public class ElementDescription : ValueObject
private ElementDescription(IElementType elem, DocNamePart whichPart, ElementRelativePosition relativePosition, int startIndex)
ClassifyTypeOfElement(elem);
RelativePosition = relativePosition;
public static ElementDescription CreateInstance(IElementType elem, DocNamePart whichPart, ElementRelativePosition relativePosition, int startIndex)
return new ElementDescription(elem, whichPart, relativePosition, startIndex);
public static ElementDescription NullElementDescription() => new(null, DocNamePart.NoPart, ElementRelativePosition.DoesNotExist, int.MinValue);
public ElementRelativePosition RelativePosition { get; set; }
public DocNamePart WhichPart { get; set; }
public IElementType Value { get; set; }
public TypeOfElement TypeOfElem { get; private set; }
public string ConnectorBefore { get; set; }
public int Start { get; private set; }
private void ClassifyTypeOfElement(object elem)
Console.WriteLine($"The object is an int with value {i}");
TypeOfElem = TypeOfElement.Int;
Console.WriteLine($"The object is an float with value {f}");
TypeOfElem = TypeOfElement.Float;
Console.WriteLine($"The object is a string with value {s}");
TypeOfElem = TypeOfElement.String;
Console.WriteLine($"The object is a DateTime with value {d}");
TypeOfElem = TypeOfElement.DateTime;
case VersionInSentence v:
TypeOfElem = v.HasVersionAnyPrefix ? TypeOfElement.VersionWithPrefix : TypeOfElement.VersionNumberOnly;
TypeOfElem = TypeOfElement.Date;
case IntervalInSentence i:
TypeOfElem = TypeOfElement.Interval;
Console.WriteLine($"The object is a InNameGUID with value {i}");
TypeOfElem = TypeOfElement.GUID;
case MedicineAndDosageInSentence i:
Console.WriteLine($"The object is a MedicineAndDosageInSentence with value {i}");
TypeOfElem = TypeOfElement.DrugNameDose;
Console.WriteLine("The object is null");
TypeOfElem = TypeOfElement.Null;
Console.WriteLine("The object is of an unknown type");
TypeOfElem = TypeOfElement.Unclassified;
public override string ToString()
return $"Element {TypeOfElem.GetDescription()} is in {WhichPart}, starting at position {(Start > -1 ? Start : "fixa")}: \n \t {Value.ToString()}";
protected override IEnumerable<IComparable> GetEqualityComponents()
yield return ConnectorBefore;
public class InNameGUID : BaseElement, IElementType
private const string Grab_GUID_treated = @"(?<GUID>[0-9a-f]{8}<>[0-9a-f]{4}<>[0-9a-f]{4}<>[0-9a-f]{4}<>[0-9a-f]{12})";
private const string Grab_GUID_BEFOREparsing = @"(?<GUID>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})";
private InNameGUID(DocNamePart namePart, string partToParse)
OriginalText = partToParse;
public static InNameGUID CreateInstance(string part, DocNamePart namePart)
var instance = new InNameGUID(namePart, part);
Console.WriteLine($"text to parse {part}");
public bool NoGUID => string.IsNullOrEmpty(GUID);
public static InNameGUID NullGUID() => new(DocNamePart.NoPart, string.Empty);
var rgx = new Regex(Grab_GUID_BEFOREparsing);
var match = rgx.Match(this.OriginalText);
Console.WriteLine($"text to parse GUID {this.OriginalText}");
StartIndex = match.Groups["GUID"].Index;
End = match.Groups["GUID"].Length - 1;
GUID = match.Groups["GUID"].Value;
Console.WriteLine($"GUID {GUID}");
Console.WriteLine($"GUID failed");
public int End { get; private set; } = -1;
public DocNamePart Part { get; private set; }
public string GUID { get; private set; }
public override string ToString()
return $"It is in {Part}, starting at position {(StartIndex > -1 ? StartIndex : "fixa")}; \n \t Value is {GUID}";
protected override IEnumerable<IComparable> GetEqualityComponents()
public class MedicineDosageForm : BaseElement, IElementType
public string Name { get; }
public string Dosage { get; }
public string Unit { get; }
public string Form { get; }
private MedicineDosageForm(string originalText, string name, string dosage, string unit, string form)
OriginalText = originalText;
public static MedicineDosageForm CreateInstance(string originalText, string name, string dosage, string unit, string form = "comprimido")
return new MedicineDosageForm(originalText, name, dosage, unit, form);
public static MedicineDosageForm NullMedicine => new(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty);
public override string ToString()
return $"Drug: {Name} {Form} of {Dosage}{Unit}";
#region Overrides of ValueObject
protected override IEnumerable<IComparable> GetEqualityComponents()
yield return OriginalText;
public class DateInSentence : BaseElement, IElementType
private readonly string _originalSentenceToParseDate;
private readonly CultureInfo _cultureInfo;
private readonly int? _maxPossibleYear;
private readonly bool _forceDdmMorMmdd;
private readonly int _minPossibleYear;
private readonly bool _acceptWildCard;
public const string GrabDatesWithMonthsInLettersOrPureNumbersFromFile = @"(?<relationandinterval>(?<temporalrelation> em | por )?(?<=\W)(?<intervalordate>(?:\d{6,8}|\d{2,3}_{1,2})|(?:\b(0?[1-9]|[12][0-9]|3[01])*(?: de )?([JFMASONDjfmasond]([a-z0-9]+)([ç]{0,1})([a-z0-9]+)*)*(?: de )?(19|20)?[0-9]{2}\b))(?<timeframe> ano | anos | mês | meses | dia | dias )?)";
public const string GrabDatesOrPureNumbersFromPartOfFile = @"(?<date>\d{6,8}|\d{2,3}_{1,2})";
public const string GrabDatesUTC = @"(?<dateUTC>(?<year>-?(?:[1-9][0-9]*)?[0-9]{4})-(?<month>1[0-2]|0[1-9])-(?<day>3[01]|0[1-9]|[12][0-9])T(?<hour>2[0-3]|[01][0-9]):(?<minute>[0-5][0-9]):(?<second>[0-5][0-9])(\\.[0-9]+)?(?<zeroUTCoffse>Z)?|(?<year>(?:[1-9][0-9]*)?[0-9]{4})(?<month>1[0-2]|0[1-9])(?<day>3[01]|0[1-9]|[12][0-9])(?<hour>2[0-3]|[01][0-9])(?<minute>[0-5][0-9])(?<second>[0-5][0-9])(\\.[0-9]+)?(?<zeroUTCoffse>Z)?)";
public const string GrabDateIntervalFromPartOfFile = @"(?<=\W)(?<interval>(?<starting>[ mçinícandouetr]+?)(?<datebegin>\d+)(?<link>[ eatéfimnldzou]+?)(?<=\W)(?<!\w-)(?<dateend>\d+))";
public const string GrabDateAndVersionDotAtEnd = @"(?<date>\d{6,8}|\d{2,3}_{1,2}) {1,2}(?<version>[vVersionão]+[\d@]+[\w@]*|[\d@]+[vVersionão]+[\w@]*).|(?<version>[vVersionão]+[\d@]+[\w@]*|[\d@]+[vVersionão]+[\w@]*) {1,2}(?<date>\d{6,8}|\d{2,3}_{1,2})\.|(?<date>\d{6,8}|\d{2,3}_{1,2})\.";
public const string WildCardForDate = "_";
#endregion Public Constants
public string DateText { get; private set; } = string.Empty;
public DateTime DateAndTime { get; private set; } = DateTime.MinValue;
public int IntervalTimeFrame => int.Parse(DateText);
public DateFormat Mask { get; private set; } = DateFormat.NoDate;
public CertaintyAboutElement CertaintyAbout { get; private set; } = CertaintyAboutElement.NonExisting;
public bool IsDDMM => _cultureInfo?.Name == "pt-BR";
private DateInSentence(string dateText, DateTime dateTime, DateFormat mask, CertaintyAboutElement certaintyAbout)
CertaintyAbout = certaintyAbout;
private DateInSentence(string originalSentenceToParseDate, CultureInfo cultureInfo, int? maxPossibleYear, bool forceDDMMorMMDD, int minPossibleYear, bool acceptWildCard)
_originalSentenceToParseDate = originalSentenceToParseDate;
_cultureInfo = cultureInfo;
_maxPossibleYear = maxPossibleYear ??= GetCurrentYearPlus(3);
_forceDdmMorMmdd = forceDDMMorMMDD;
_minPossibleYear = minPossibleYear;
_acceptWildCard = acceptWildCard;
public static DateInSentence NullDate => new(string.Empty, DateTime.MinValue, DateFormat.NoDate, CertaintyAboutElement.NonExisting);
public static DateInSentence ChangeMask(DateInSentence date, DateFormat newMask)
return CreateInstance(date.DateText, date.DateAndTime, newMask);
public static DateInSentence ChangeToYYYY(DateInSentence date, DateFormat newMask)
if (date.DateText.Length != 4)
throw new ArgumentException("Can only change mask of DDMM or MMDD to YYYY");
return CreateInstance(date.DateText, date.DateAndTime, DateFormat.yyyy);
public static DateInSentence ChangeToMMDD(DateInSentence date, DateFormat newMask)
if (date.DateText.Length != 4)
throw new ArgumentException("Can only change mask of DDMM or YYYY to MMDD");
return CreateInstance(date.DateText, date.DateAndTime, DateFormat.MMdd);
public static DateInSentence ChangeToDDMM(DateInSentence date, DateFormat newMask)
if (date.DateText.Length != 4)
throw new ArgumentException("Can only change mask of MMDD or YYYY to DDMM");
return CreateInstance(date.DateText, date.DateAndTime, DateFormat.ddMM);
public static DateInSentence CreateInstanceTimeFrame(string dateText, DateFormat mask, CertaintyAboutElement certaintyAbout = CertaintyAboutElement.AbsolutelyCertain)
return new DateInSentence(dateText, DateTime.MinValue, mask, certaintyAbout);
public static DateInSentence CreateInstance(string dateText, DateTime dateTime, DateFormat mask, CertaintyAboutElement certaintyAbout = CertaintyAboutElement.AbsolutelyCertain)
return new DateInSentence(dateText, dateTime, mask, certaintyAbout);
public static DateInSentence CreateInstance(string dateToParse, CultureInfo cultureInfo, int? maxPossibleYear, bool forceDDMMorMMDD = false, int minPossibleYear = 1990, bool acceptWildCard = true)
var dateParsing = new DateInSentence(dateToParse, cultureInfo, maxPossibleYear, forceDDMMorMMDD, minPossibleYear, acceptWildCard);
var dateExtracted = dateParsing.GetDate(dateToParse, (-1, -1));
if (dateExtracted.IsFailure) return DateInSentence.NullDate;
var maskForDateParsing = string.Empty;
DateTime parsedDate = DateTime.MinValue;
var raw = dateExtracted.Value;
if (raw.Length == DateFormat.sortable.GetDescription().Length)
dateParsing.Mask = DateFormat.sortable;
else if (raw.Length == 8)
dateParsing.Mask = dateParsing.IsDDMM ? DateFormat.ddMMyyyy : DateFormat.MMddyyyy;
else if (raw.Length == 6)
dateParsing.Mask = DateFormat.MMyyyy;
else if (raw.Length == 4)
var yyyyToTestIfWithinAllowedRange = DateTime.MinValue;
var maybeDDMMorMMDD = IsItPossibleToBeDDMMOrMMDD(raw, cultureInfo);
var maybeYYYY = DateTime.TryParseExact(raw, DateFormat.yyyy.GetDescription(), cultureInfo, DateTimeStyles.None, out yyyyToTestIfWithinAllowedRange);
if ((maybeDDMMorMMDD && !maybeYYYY) || forceDDMMorMMDD)
dateParsing.Mask = dateParsing.IsDDMM ? DateFormat.ddMM : DateFormat.MMdd;
else if (!maybeDDMMorMMDD && maybeYYYY)
dateParsing.Mask = DateFormat.yyyy;
else if (maybeDDMMorMMDD && maybeYYYY)
dateParsing.CertaintyAbout = CertaintyAboutElement.InformedGuess;
if (yyyyToTestIfWithinAllowedRange >= new DateTime(minPossibleYear, 1, 1) && yyyyToTestIfWithinAllowedRange <= new DateTime(maxPossibleYear.Value, 1, 1))
dateParsing.Mask = DateFormat.yyyy;
dateParsing.Mask = dateParsing.IsDDMM ? DateFormat.ddMM : DateFormat.MMdd;
else if (maybeDDMMorMMDD && maybeYYYY)
dateParsing.Mask = DateFormat.NoDate;
dateParsing.CertaintyAbout = CertaintyAboutElement.NonExisting;
else if (raw.Length == 2)
throw new NotImplementedException("InferMaskAndFormatForDateParsing: dateParsing.Length == 2");
if (raw.Contains(WildCardForDate) && raw.Length == 4)
dateParsing.Mask = DateFormat.yyyy;
dateParsing.DateText = raw;
dateParsing.CertaintyAbout = CertaintyAboutElement.AbsolutelyCertain;
if (!raw.Contains(WildCardForDate) && raw.Length == 7)
dateParsing.Mask = DateFormat.MMMyyyy;
dateParsing.CertaintyAbout = CertaintyAboutElement.AbsolutelyCertain;
throw new NotImplementedException("InferMaskAndFormatForDateParsing: dateParsing is not digit, ie, MMM or MMMM or ddd or dd or tt");
if (DateTime.TryParseExact(raw, dateParsing.Mask.GetDescription(), cultureInfo, DateTimeStyles.None, out parsedDate))
dateParsing.DateAndTime = parsedDate;
dateParsing.DateText = raw;
dateParsing.ElementValue = Result.Success(raw);
dateParsing.ElementValue = Result.Failure<string>("No date stamp in this file name");
return DateInSentence.NullDate;
public static DateInSentence CreateInstanceFromSentence(string dateToParse, CultureInfo cultureInfo, (int start, int end) forbiddenZoneCoordinates, int? maxPossibleYear, bool forceDDMMorMMDD = false, int minPossibleYear = 1990, bool acceptWildCard = true)
var hasDate = GetDateStatic(dateToParse, cultureInfo, forbiddenZoneCoordinates, acceptWildCard);
return DateInSentence.NullDate;
return CreateInstance(hasDate.Value, cultureInfo, maxPossibleYear, forceDDMMorMMDD, minPossibleYear, acceptWildCard);
public static Result<DateInSentence> Update(string date, DateInSentence valueDateInSentence)
var tryDate = CreateInstance(date, valueDateInSentence._cultureInfo, valueDateInSentence._maxPossibleYear, valueDateInSentence._forceDdmMorMmdd, valueDateInSentence._minPossibleYear, valueDateInSentence._acceptWildCard);
return Result.Failure<DateInSentence>("Invalid date");
return Result.Success(tryDate);
public Result<string> GetDate(string partToTest, (int start, int end) forbiddenZoneCoordinates)
if (string.IsNullOrEmpty(partToTest) || DocNameHelper.DifficultyToTestPart(partToTest))
return Result.Failure<string>("No date stamp in this file name");
var hasDate = ReturnDateResult(GrabDatesUTC, partToTest, "dateUTC", "No date stamp in this file name", _cultureInfo, forbiddenZoneCoordinates);
hasDate = ReturnDateResult(GrabDatesOrPureNumbersFromPartOfFile, partToTest, "date", "No date stamp in this file name", _cultureInfo, forbiddenZoneCoordinates);
hasDate = ReturnDateResult(GrabDatesWithMonthsInLettersOrPureNumbersFromFile, partToTest, "intervalordate", "No date stamp in this file name", _cultureInfo, forbiddenZoneCoordinates);
hasDate = FilterAbsurdDates(hasDate, _cultureInfo, _acceptWildCard, "No date stamp in this file name");
public static Result<string> GetDateStatic(string partToTest, CultureInfo cultureInfo, (int start, int end) forbiddenZoneCoordinates, bool acceptWildCard = true)
if (string.IsNullOrEmpty(partToTest) || DocNameHelper.DifficultyToTestPart(partToTest))
return Result.Failure<string>("No date stamp in this file name");
var hasDate = ReturnDateResult(GrabDatesUTC, partToTest, "dateUTC", "No date stamp in this file name", cultureInfo, forbiddenZoneCoordinates);
hasDate = ReturnDateResult(GrabDatesOrPureNumbersFromPartOfFile, partToTest, "date", "No date stamp in this file name", cultureInfo, forbiddenZoneCoordinates);
hasDate = ReturnDateResult(GrabDatesWithMonthsInLettersOrPureNumbersFromFile, partToTest, "intervalordate", "No date stamp in this file name", cultureInfo, forbiddenZoneCoordinates);
hasDate = FilterAbsurdDates(hasDate, cultureInfo, acceptWildCard, "No date stamp in this file name");
internal static int GetCurrentYearPlus(int toAddCurrent) => DateTime.Now.Year + toAddCurrent;
internal static bool IsItPossibleToBeDDMMOrMMDD(string dateToTest, CultureInfo cultureInfo)
if (dateToTest.Length != 4)
return DateTime.TryParseExact(dateToTest, DateFormat.ddMM.GetDescription(), cultureInfo, DateTimeStyles.None, out _) || DateTime.TryParseExact(dateToTest, DateFormat.MMdd.GetDescription(), cultureInfo, DateTimeStyles.None, out _);
private static Result<string> FilterAbsurdDates(Result<string> hasDate, CultureInfo cultureInfo, bool acceptWildCard = true, string errorMsg = "No date found", int numberOfYearsToConsiderAbsurd = 99)
DateTime testDate = DateTime.MinValue;
string dateWithoutSpace = string.Empty;
if (hasDate.Value.DoesNotContainAnySpace())
dateWithoutSpace = hasDate.Value;
var dateCandidates = hasDate.Value.Split(' ');
foreach (var element in dateCandidates)
if (element.Length > 3 && element.Length < 8)
dateWithoutSpace = element;
if (DocNameHelper.DateTryParseExact(dateWithoutSpace, out testDate, new CultureInfo("pt-BR")))
if (testDate.IsThisDateNullOrDefault())
return Result.Failure<string>(errorMsg);
if (Math.Abs(testDate.YearsBetweenNowAndDate()) >= numberOfYearsToConsiderAbsurd)
return Result.Failure<string>($"Cannot allow set date so many years ({testDate.YearsBetweenNowAndDate()}) far from today");
return Result.Success(dateWithoutSpace);
if (acceptWildCard && dateWithoutSpace.Contains(WildCardForDate))
return Result.Success(dateWithoutSpace);
return Result.Failure<string>($"Invalid date resulting in {testDate.ToString()}");
private static bool InTimeRangeAllowed(int numberOfYearsToConsiderAbsurd, DateTime testDate)
var tested = Math.Abs(testDate.YearsBetweenNowAndDate());
return tested < numberOfYearsToConsiderAbsurd;
public static Result<string> ReturnDateResult(string pattern, string part, string groupName, string errorMsg, CultureInfo cultureInfo, (int start, int end) forbiddenZoneCoordinates)
var match = DocNameHelper.GetMatch(pattern, part, groupName, errorMsg, out result);
if (!result.IsFailure && DocNameHelper.OutOfForbiddenZoneIfSamePart(groupName, match, forbiddenZoneCoordinates.start, forbiddenZoneCoordinates.end))
if (DocNameHelper.DateTryParseExact(part, out var testDate, cultureInfo))
result = !testDate.IsThisDateNullOrDefault() ? Result.Success(part) : Result.Failure<string>(errorMsg);
public override string ToString()
return $"{DateText} with mask {Mask}: {DateAndTime}; certainty: {CertaintyAbout}";
#endregion Private Methods
#region Overrides of ValueObject
protected override IEnumerable<IComparable> GetEqualityComponents()
yield return DateAndTime;
yield return CertaintyAbout;
public class IntervalInSentence : BaseElement, IElementType
#region Private Constants
private readonly string _cultureInfo;
private readonly bool _sameFrameIntervalIsAllowed;
private readonly bool _forceBeginDatePreviousYearIfReasonable;
private readonly string _errorMsg;
private Result<string> _candidateBegin;
private Result<string> _candidateEnd;
#endregion Private Constants
public const string GrabDatesWithMonthsInLettersOrPureNumbersFromFile = @"(?<relationandinterval>(?<temporalrelation> em | por )?(?<=\W)(?<intervalordate>(?:\d{6,8}|\d{2,3}_{1,2})|(?:\b(0?[1-9]|[12][0-9]|3[01])*(?: de )?([JFMASONDjfmasond]([a-z0-9]+)([ç]{0,1})([a-z0-9]+)*)*(?: de )?(19|20)?[0-9]{2}\b))(?<timeframe> ano | anos | mês | meses | dia | dias )?)";
public const string GrabDateIntervalFromPartOfFile = @"(?<=\W)(?<interval>(?<starting>[ mçinícandouetr]+?)(?<datebegin>\d+)(?<link>[ eatéfimnldzou]+?)(?<=\W)(?<!\w-)(?<dateend>\d+))";
#endregion Public Constants
public IntervalType IntervalType { get; private set; }
public string OriginalInterval { get; private set; }
public Result<string> Interval { get; private set; }
public string TextTemporalRelation { get; private set; }
public string TextBetween { get; private set; }
public string TimeFrame { get; private set; }
public DateInSentence DateBegin { get; private set; }
public DateInSentence DateEnd { get; private set; }
public TypeOfElement TypeOfElem => TypeOfElement.Interval;
public CertaintyAboutElement CertaintyAboutDateBegin => DateBegin?.CertaintyAbout ?? CertaintyAboutElement.NonExisting;
public CertaintyAboutElement CertaintyAboutDateEnd => DateEnd?.CertaintyAbout ?? CertaintyAboutElement.NonExisting;
public bool DateBeginHadToGoBackOneYear { get; private set; }
public static IntervalInSentence Null
var nullInterval = new IntervalInSentence(string.Empty, CultureInfo.CurrentCulture, false, false, "No interval date stamp in this file name");
nullInterval.Interval = Result.Failure<string>(nullInterval._errorMsg);
private IntervalInSentence()
private IntervalInSentence(string originalInterval, CultureInfo cultureInfo, bool sameFrameIntervalIsAllowed, bool forceBeginDatePreviousYearIfReasonable, string errorMsg)
_cultureInfo = cultureInfo.Name;
_sameFrameIntervalIsAllowed = sameFrameIntervalIsAllowed;
_forceBeginDatePreviousYearIfReasonable = forceBeginDatePreviousYearIfReasonable;
OriginalInterval = originalInterval;
internal static IntervalInSentence CreateInstance(string interval, CultureInfo cultureInfo, bool forceBeginDatePreviousYearIfReasonable = false, bool sameFrameIntervalIsAllowed = false, string errorMsg = "No interval date stamp in this file name")
var intervalInSentence = new IntervalInSentence(interval, cultureInfo, sameFrameIntervalIsAllowed, forceBeginDatePreviousYearIfReasonable, errorMsg);
return !intervalInSentence.GetIntervalDates(interval) ? IntervalInSentence.Null : intervalInSentence;
private bool IsDDMM => _cultureInfo == "pt-BR";
private bool GetIntervalDates(string partToTest)
if (string.IsNullOrEmpty(partToTest) || DocNameHelper.DifficultyToTestPart(partToTest))
var hasInterval = DocNameHelper.ReturnResult(GrabDateIntervalFromPartOfFile, partToTest, "interval", _errorMsg);
var allErrors = string.Empty;
if (hasInterval.IsSuccess)
_candidateBegin = DocNameHelper.ReturnResult(GrabDateIntervalFromPartOfFile, partToTest, "datebegin", _errorMsg);
_candidateEnd = DocNameHelper.ReturnResult(GrabDateIntervalFromPartOfFile, partToTest, "dateend", _errorMsg);
if (_candidateBegin.IsFailure || _candidateEnd.IsFailure)
ElementValue = Result.Failure<string>( $"No date stamp in this file name because: \n {_errorMsg}");
var intervalDates = TryCompareIntervalDates(_candidateBegin.Value, _candidateEnd.Value);
if (intervalDates.dateBegin.IsFailure && intervalDates.dateEnd.IsFailure)
ElementValue = Result.Failure<string>($"No date stamp in this file name because: \n {_errorMsg}");
DateBegin = intervalDates.dateBegin.Value;
DateEnd = intervalDates.dateEnd.Value;
TextTemporalRelation = DocNameHelper.ReturnResult(GrabDateIntervalFromPartOfFile, partToTest, "starting", _errorMsg).Value;
TextBetween = DocNameHelper.ReturnResult(GrabDateIntervalFromPartOfFile, partToTest, "link", _errorMsg).Value;
IntervalType = IntervalType.Normal;
TimeFrame = string.Empty;
ElementValue = Result.Success(hasInterval.Value);
if (hasInterval.IsFailure)
var match = DocNameHelper.GetMatch(GrabDatesWithMonthsInLettersOrPureNumbersFromFile, partToTest, "relationandinterval", _errorMsg, out var result);
hasInterval = DocNameHelper.ReturnResult(GrabDatesWithMonthsInLettersOrPureNumbersFromFile, partToTest, "intervalordate", _errorMsg);
if (result.Equals(hasInterval))
Interval = Result.Failure<string>(_errorMsg);
ElementValue = Result.Failure<string>($"No date stamp in this file name because: \n {_errorMsg}");
IntervalType = IntervalType.TemporalClue;
_candidateBegin = DocNameHelper.ReturnResult(GrabDatesWithMonthsInLettersOrPureNumbersFromFile, partToTest, "intervalordate", _errorMsg);
_candidateEnd = _candidateBegin;
if (_candidateBegin.IsFailure)
TextTemporalRelation = DocNameHelper.ReturnResult(GrabDatesWithMonthsInLettersOrPureNumbersFromFile, partToTest, "temporalrelation", _errorMsg).Value;
TextBetween = string.Empty;
TimeFrame = DocNameHelper.ReturnResult(GrabDatesWithMonthsInLettersOrPureNumbersFromFile, partToTest, "timeframe", _errorMsg).Value;
DateBegin = DateInSentence.CreateInstanceTimeFrame(_candidateBegin.Value, DetermineTimeFrameType(result.Value));
ElementValue = Result.Success(hasInterval.Value);
return _candidateBegin.IsSuccess && _candidateEnd.IsSuccess;
private string CompoundErrorMsgs (string @base, string first, string second = "")
if (string.IsNullOrEmpty(first)) return string.Empty;
var allErrors = @$"{@base}\n{first}";
allErrors += string.IsNullOrEmpty(_errorMsg) ? string.Empty : $";\n{second}";
private (Result<DateInSentence> dateBegin, Result<DateInSentence> dateEnd) TryCompareIntervalDates(string dateBegin, string dateEnd)
var errorMsg = "because BeginDate is After EndDate";
if (dateBegin.IsDigit() && dateEnd.IsDigit())
if (dateBegin.Length == DateFormat.sortable.GetDescription().Length)
var beginDDMMDateIsInPreviousYear = CompareDatesWithSameFormat(dateBegin, dateEnd, out var format, out var validDates);
if (beginDDMMDateIsInPreviousYear)
return (Result.Success(DateInSentence.CreateInstance(dateBegin, validDates.dateStarted, format)), Result.Success(DateInSentence.CreateInstance(dateEnd, validDates.dateEnded, format)));
var formatEnd = IsDDMM ? DateFormat.ddMMyyyy : DateFormat.MMddyyyy;
var dateEndIsDDMM = DateTime.TryParseExact(dateEnd, formatEnd.GetDescription(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out var dateEnded);
if (dateBegin.Length == 8)
var beginDDMMDateIsInPreviousYear = CompareDatesWithSameFormat(dateBegin, dateEnd, out var format, out var validDates);
if (beginDDMMDateIsInPreviousYear)
return (Result.Success(DateInSentence.CreateInstance(dateBegin, validDates.dateStarted, format)), Result.Success(DateInSentence.CreateInstance(dateEnd, validDates.dateEnded, format)));
else if (dateBegin.Length == 6)
throw new NotImplementedException("I did not implemented 'de MMyyyy até ddMMyyyy'");
else if (dateBegin.Length == 4)
var dateBeginIsDDMM = DateTime.TryParseExact(dateBegin + dateEnded.Year, formatEnd.GetDescription(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out var ddMMBegin);
errorMsg = "because BeginDate is After EndDate";
else if (IsBeginDateReallyBeforeEndDate(ddMMBegin, dateEnded))
var formatBegin = IsDDMM ? DateFormat.ddMM : DateFormat.MMdd;
if (DateBeginHadToGoBackOneYear)
ddMMBegin = ddMMBegin.AddYears(-1);
return (Result.Success(DateInSentence.CreateInstance(dateBegin, ddMMBegin, formatBegin)), Result.Success(DateInSentence.CreateInstance(dateEnd, dateEnded, formatEnd)));
else if (dateBegin.Length == 2)
var dayBegin = int.Parse(dateBegin);
if ((dayBegin > 0 && dayBegin < dateEnded.Day) || ((dayBegin == dateEnded.Day) && _sameFrameIntervalIsAllowed))
var dayInterval = Result.Success(DateInSentence.CreateInstance(dateBegin, new DateTime(dateEnded.Year, dateEnded.Month, dayBegin), DateFormat.dd));
return (dayInterval, Result.Success(DateInSentence.CreateInstance(dateEnd, dateEnded, formatEnd)));
errorMsg = "because BeginDate is After EndDate";
formatEnd = DateFormat.MMyyyy;
dateEndIsDDMM = DateTime.TryParseExact(dateEnd, formatEnd.GetDescription(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out dateEnded);
if (dateBegin.Length == 8)
throw new NotImplementedException("I did not implemented 'de ddMMyyyy até MMyyyy'");
else if (dateBegin.Length == 6)
var dateBeginIsDDMM = DateTime.TryParseExact(dateBegin, formatEnd.GetDescription(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out var ddMMBegin);
if (IsBeginDateReallyBeforeEndDate(ddMMBegin, dateEnded))
return (Result.Success(DateInSentence.CreateInstance(dateBegin, ddMMBegin, formatEnd)), Result.Success(DateInSentence.CreateInstance(dateEnd, dateEnded, formatEnd)));
errorMsg = "because BeginDate is After EndDate";
else if (dateBegin.Length == 4)
throw new NotImplementedException("I did not implemented 'de ddMM até MMyyyy'");
else if (dateBegin.Length == 2)
if (dateBegin.Length == 8)
else if (dateBegin.Length == 6)
else if (dateBegin.Length == 4)
var result = DecideIfDateEndIsYYYYOrDDMM(dateBegin, dateEnd, null, sameFrameIntervalIsAllowed: _sameFrameIntervalIsAllowed);
if (result.dateBegin.CertaintyAbout != CertaintyAboutElement.NonExisting)
return (Result.Success(result.dateBegin), Result.Success(result.dateEnd));
errorMsg = "not existing BeginDate or EndDate";
else if (dateBegin.Length == 2)
errorMsg = "No interval date stamp in this file name";
return (Result.Failure<DateInSentence>(errorMsg), Result.Failure<DateInSentence>(errorMsg));
private bool CompareDatesWithSameFormat(string dateBegin, string dateEnd, out DateFormat format, out (bool dateBeginIsDDMM, DateTime dateStarted, bool dateEndIsDDMM, DateTime dateEnded) validDates)
var date = DateInSentence.CreateInstance(dateBegin, new CultureInfo(_cultureInfo), 2025, false);
(var mask, format) = (date.Mask.GetDescription(), date.Mask);
validDates = TryToParseDatesAsDDMM_MMDD(dateBegin, dateEnd, mask);
bool beginDDMMDateIsInPreviousYear = false;
if (validDates.dateStarted == DateTime.MinValue || validDates.dateEnded == DateTime.MinValue)
return beginDDMMDateIsInPreviousYear;
beginDDMMDateIsInPreviousYear = IsDDMMBeginDateReallyBeforeEndDate(dateBegin, dateEnd, format, _sameFrameIntervalIsAllowed);
return beginDDMMDateIsInPreviousYear;
private (DateInSentence dateBegin, DateInSentence dateEnd) DecideIfDateEndIsYYYYOrDDMM(string dateBeginToTest, string dateEndToTest, int? maxPossibleYear, int minPossibleYear = 1990, bool sameFrameIntervalIsAllowed = false)
maxPossibleYear ??= DateInSentence.GetCurrentYearPlus(3);
var (isDateEndDubious, isDateBeginDubious, certaintyAboutYYYY) = DecideDegreeOfCertaintyAboutDates(dateBeginToTest, dateEndToTest);
var dateBeginTry = DateInSentence.CreateInstance(dateBeginToTest, new CultureInfo(_cultureInfo), 2025, false);
var (_, formatForDateBeginTry) = (dateBeginTry.Mask.GetDescription(), dateBeginTry.Mask);
var dateBegin = DateInSentence.NullDate;
var dateBeginIsYYYY = false;
var dateBeginIsDDMM = false;
var dateEnd = DateInSentence.NullDate;
var dateEndIsYYYY = false;
var dateEndIsDDMM = false;
var (dateEnded, endDateMaybeYYYY) = TryToParseDateAsYYYY(dateEndToTest);
var (dateStarted, beginDateMaybeYYYY) = TryToParseDateAsYYYY(dateBeginToTest);
endDateMaybeYYYY = IsValidEndDateYYYY(dateStarted, dateEnded, minPossibleYear, maxPossibleYear.Value, sameFrameIntervalIsAllowed);
(dateBeginIsYYYY, dateEndIsYYYY) = DetermineIfIntervalDatesShouldBeYYYY(isDateEndDubious, isDateBeginDubious, endDateMaybeYYYY, beginDateMaybeYYYY, dateEndIsYYYY, dateBeginIsYYYY);
var beginCannotBeDDMMOrMMDD = !DateInSentence.IsItPossibleToBeDDMMOrMMDD(dateBeginToTest, new CultureInfo(_cultureInfo));
if (beginCannotBeDDMMOrMMDD && !endDateMaybeYYYY)
if (dateStarted != dateEnded)
return (DateInSentence.NullDate, DateInSentence.NullDate);
if (dateStarted == dateEnded && !sameFrameIntervalIsAllowed)
return (DateInSentence.NullDate, DateInSentence.NullDate);
if (dateBeginIsYYYY || beginCannotBeDDMMOrMMDD)
(dateStarted, dateBeginIsYYYY) = TryToParseDateAsYYYY(dateBeginToTest);
formatForDateBeginTry = IsDDMM ? DateFormat.ddMM : DateFormat.MMdd;
(dateBeginIsDDMM, dateStarted, dateEndIsDDMM, dateEnded) = TryToParseDatesAsDDMM_MMDD(dateBeginToTest, dateEndToTest, formatForDateBeginTry.ToString());
dateEndIsYYYY = DateTime.TryParseExact(dateEndToTest, DateFormat.yyyy.GetDescription(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out dateEnded);
return (dateBegin, dateEnd);
dateBegin = DateInSentence.CreateInstance(dateBeginToTest, dateStarted, DateFormat.yyyy, certaintyAboutYYYY);
dateEnd = DateInSentence.CreateInstance(dateEndToTest, dateEnded, DateFormat.yyyy, certaintyAboutYYYY);
else if (dateBeginIsDDMM)
if (!dateEndIsDDMM || !IsDDMMBeginDateReallyBeforeEndDate(dateBeginToTest, dateEndToTest, formatForDateBeginTry, sameFrameIntervalIsAllowed))
return (dateBegin, dateEnd);
dateBegin = DateInSentence.CreateInstance(dateBeginToTest, dateStarted, formatForDateBeginTry, certaintyAboutYYYY);
dateEnd = DateInSentence.CreateInstance(dateEndToTest, dateEnded, formatForDateBeginTry, certaintyAboutYYYY);
return (dateBegin, dateEnd);
private (bool isDateEndDubious, bool isDateBeginDubious, CertaintyAboutElement certaintyAboutYYYY) DecideDegreeOfCertaintyAboutDates(string dateBeginToTest, string dateEndToTest)
var dubiousDate = _cultureInfo == "pt-BR" ? DocNameHelper.dubiousDDMMOrYYYY() : DocNameHelper.dubiousMMDDOrYYYY();
var isDateEndDubious = dubiousDate.Contains(dateEndToTest);
var isDateBeginDubious = dubiousDate.Contains(dateBeginToTest);
var certaintyAboutYYYY = isDateBeginDubious && isDateEndDubious ? CertaintyAboutElement.InformedGuess : CertaintyAboutElement.AbsolutelyCertain;
return (isDateEndDubious, isDateBeginDubious, certaintyAboutYYYY);
private bool IsDDMMBeginDateReallyBeforeEndDate(string dateBegin, string dateEnd, DateFormat dateFormat, bool sameFrameIntervalIsAllowed = false)
var beginDateValid = DateTime.TryParseExact(dateBegin, dateFormat.GetDescription(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out var beginDate);
var endDateValid = DateTime.TryParseExact(dateEnd, dateFormat.GetDescription(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out var endDate);
if (!beginDateValid || !endDateValid)
return IsBeginDateReallyBeforeEndDate(beginDate, endDate);
private bool IsBeginDateReallyBeforeEndDate(DateTime dateBegin, DateTime dateEnd)
DateBeginHadToGoBackOneYear = false;
var isBefore = _sameFrameIntervalIsAllowed ? dateBegin <= dateEnd : dateBegin < dateEnd;
if (!isBefore && _forceBeginDatePreviousYearIfReasonable)
var dateBeginPreviousYear = dateBegin.AddYears(-1);
isBefore = _sameFrameIntervalIsAllowed ? dateBeginPreviousYear <= dateEnd : dateBeginPreviousYear < dateEnd;
DateBeginHadToGoBackOneYear = isBefore;
private (bool dateBeginIsYYYY, bool dateEndIsYYYY) DetermineIfIntervalDatesShouldBeYYYY(bool isDateEndDubious, bool isDateBeginDubious, bool endDateMaybeYYYY, bool beginDateMaybeYYYY, bool dateEndIsYYYY, bool dateBeginIsYYYY)
if (IfNoDateIsDubious(isDateEndDubious, isDateBeginDubious))
return (endDateMaybeYYYY, beginDateMaybeYYYY);
if (AtLeastSomeDateIsDubiousAndBothDatesMaybeYYYY(endDateMaybeYYYY, beginDateMaybeYYYY))
return (dateBeginIsYYYY, dateEndIsYYYY);
private bool AtLeastSomeDateIsDubiousAndBothDatesMaybeYYYY(bool endDateMaybeYYYY, bool beginDateMaybeYYYY)
return endDateMaybeYYYY && beginDateMaybeYYYY;
private bool IfNoDateIsDubious(bool isDateEndDubious, bool isDateBeginDubious)
return !isDateEndDubious && !isDateBeginDubious;
private bool IsValidEndDateYYYY(DateTime dateBegin, DateTime dateEnd, int minPossibleYear, int maxPossibleYear, bool sameYearIntervalIsAllowed)
if (!IsBeginDateReallyBeforeEndDate(dateBegin, dateEnd))
return dateEnd.Year >= minPossibleYear && dateEnd.Year <= maxPossibleYear;
private (DateTime dateParsed, bool tryParseExact) TryToParseDateAsYYYY(string dateToTest)
var tryParseExact = DateTime.TryParseExact(dateToTest, DateFormat.yyyy.ToString(), new CultureInfo(_cultureInfo), DateTimeStyles.None, out var dateParsed);
return (dateParsed, tryParseExact);
private (bool dateBeginIsDDMM, DateTime dateStarted, bool dateEndIsDDMM, DateTime dateEnded) TryToParseDatesAsDDMM_MMDD(string dateBeginToTest, string dateEndToTest, string maskForDDMM)
var dateBeginIsDDMM = DateTime.TryParseExact(dateBeginToTest, maskForDDMM, new CultureInfo(_cultureInfo), DateTimeStyles.None, out var dateStarted);
var dateEndIsDDMM = DateTime.TryParseExact(dateEndToTest, maskForDDMM, new CultureInfo(_cultureInfo), DateTimeStyles.None, out var dateEnded);
return (dateBeginIsDDMM, dateStarted, dateEndIsDDMM, dateEnded);
private DateFormat DetermineTimeFrameType(string originalText)
if (originalText.Contains("dia"))
return DateFormat.NumDays;
if (originalText.Contains("mês") || originalText.Contains("meses"))
return DateFormat.NumMonths;
if (originalText.Contains("ano"))
return DateFormat.NumYears;
return DateFormat.Unknown;
#endregion Private Methods
private bool IsIntervalValid(string partToTest)
var validBeginInterval = DocNameHelper.DateTryParseExact(_candidateBegin.Value, out var beginInterval, CultureInfo.CurrentCulture);
var validEndInterval = DocNameHelper.DateTryParseExact(_candidateEnd.Value, out var endInterval, CultureInfo.CurrentCulture);
var isValid = beginInterval < endInterval;
public override string ToString()
return $"Interval is type {IntervalType.GetDescription()}. \n \t Start Date is {DateBegin.ToString()} (certainty: {CertaintyAboutDateBegin.GetDescription()}) \n \t End Date is {DateEnd.ToString()} (certainty: {CertaintyAboutDateEnd.GetDescription()})";
#region Overrides of ValueObject
protected override IEnumerable<IComparable> GetEqualityComponents()
yield return _cultureInfo;
yield return _sameFrameIntervalIsAllowed;
yield return _forceBeginDatePreviousYearIfReasonable;
yield return OriginalInterval;
yield return DateBeginHadToGoBackOneYear;
yield return TextBetween;
yield return TextTemporalRelation;
yield return IntervalType;
yield return CertaintyAboutDateBegin;
yield return CertaintyAboutDateEnd;
public class VersionInSentence : BaseElement, IElementType
private readonly string _originalSentenceToParseDate;
public const string GrabVersionFromFile = @"(?<version>\sv[ersionão]*[\d@]+[\w@]*|[\d@]+v[ersionão]*[\w@]*)";
#endregion Public Constants
public string Version { get; private set; }
public string VersionPrefix => Version.ReturnOnlyNonNumericCharacters();
public int VersionNumber => Version.ReturnOnlyNumbersAsInt()!.Value;
public bool HasVersionAnyPrefix => VersionPrefix.Length > 0;
public TypeOfElement TypeOfElem => HasVersionAnyPrefix ? TypeOfElement.VersionWithPrefix : TypeOfElement.VersionNumberOnly;
private VersionInSentence(string partToTest)
_originalSentenceToParseDate = partToTest;
ElementValue = Result.Failure<string>("No file version");
public static VersionInSentence CreateInstance(string partToTest)
if (string.IsNullOrEmpty(partToTest) || DocNameHelper.DifficultyToTestPart(partToTest)) return NullVersion;
var instance = new VersionInSentence(partToTest);
instance.ElementValue = instance.GetVersion();
if (instance.ElementValue.IsFailure)
instance.Version = instance.ElementValue.Value;
public static VersionInSentence NullVersion => new(string.Empty);
private Result<string> GetVersion()
var partToTest = _originalSentenceToParseDate;
var version = GetVersionFromPart(partToTest);
if (!version.IsFailure && version.Value.IsNumber())
return TestVersionNumberOnly(version.Value);
if (version.IsFailure && partToTest.Length < 3 && partToTest.IsNumber())
return TestVersionNumberOnly(partToTest);
if (version.IsFailure && partToTest.ReturnOnlyNumbers().Length > 0 && partToTest.ReturnOnlyNumbers().Length < 3 && partToTest.ReturnOnlyNumbers().IsNumber())
return TestVersionNumberOnly(partToTest.ReturnOnlyNumbers());
private static Result<string> TestVersionNumberOnly(string candidateForVersion)
var candidate = int.Parse(candidateForVersion);
if (candidate < 1 || candidate > 20)
return Result.Failure<string>("No file version");
return Result.Success(candidate.ToString());
private static Result<string> GetVersionFromPart(string partToTest)
var version = DocNameHelper.ReturnResult(GrabVersionFromFile, partToTest, "version", "No file version");
if (version.IsFailure && !char.IsWhiteSpace(partToTest, 0))
version = DocNameHelper.ReturnResult(GrabVersionFromFile, $" {partToTest}", "version", "No file version");
public static Result<string> TryRecoverFileVersionOnlyNumber(Result<string> fileDateOrInterval, Result<string> partNameToTest)
if (fileDateOrInterval.IsSuccess)
rest = partNameToTest.Value.Replace(fileDateOrInterval.Value, string.Empty).Trim();
int.TryParse(rest, out tryVersion);
if (tryVersion is > 0 and < 20)
return Result.Success(tryVersion.ToString());
var restNum = rest.ReturnOnlyNumbersToArray();
if (restNum.Length != 1 || !int.TryParse(restNum[0].ToString(), out tryVersion))
return Result.Failure<string>("No file version");
return tryVersion is > 0 and < 20 ? Result.Success(tryVersion.ToString()) : Result.Failure<string>("No file version");
public override string ToString()
return $"It has a Value '{Version}'";
#region Overrides of ValueObject
protected override IEnumerable<IComparable> GetEqualityComponents()
yield return _originalSentenceToParseDate;
public class MedicineAndDosageInSentence : BaseElement
#region Private Constants
#endregion Private Constants
public const string GrabDoseAndUnitOfMedicinesFromPartOfFile = @"(?<=-|- )?(?<complete>(?<medicine>(?:(?!RECEITUÁRIO CONTROLE ESPECIAL)\w+ ){1,4})(?<=[ ]{1,2})(?<dosewithunit>(?<dose>[\d,.]+|[\d]+_[\d]+)[ ]{0,2}(?<unit>mg|comp|cp|UI|g)))(?=[ .-]?)";
#endregion Public Constants
public string Name { get; private set; }
public string Dosage { get; set; }
public string Unit { get; set; }
public string Form { get; set; }
private MedicineAndDosageInSentence(string originalText, string name, string dosage, string unit, string form)
OriginalText = originalText;
private MedicineAndDosageInSentence(string originalText)
OriginalText = originalText;
public static MedicineAndDosageInSentence CreateInstance(string originalText)
if (string.IsNullOrEmpty(originalText))
var instance = new MedicineAndDosageInSentence(originalText);
instance.TryFindMedicineDosageForm();
return instance.ElementValue.IsFailure ? NullMedicine : instance;
public static MedicineAndDosageInSentence NullMedicine => new(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty);
private void TryFindMedicineDosageForm()
var rgx = new Regex(GrabDoseAndUnitOfMedicinesFromPartOfFile);
var match = rgx.Match(OriginalText);
OriginalText = match.Groups["complete"].Value;
Name = match.Groups["medicine"].Value.Replace("CONTROLE ESPECIAL", string.Empty).Trim();
Dosage = match.Groups["dose"].Value;
Unit = match.Groups["unit"].Value;
var criteria = new string[]{"Receita de Antibióticos", "Receita de Psicotrópicos"};
var medicines = GetWordsThatPointsToType(criteria);
foreach (var medicine in medicines)
if (!OriginalText.ToLowerInvariant().Contains(medicine.ToLowerInvariant()))
Name = medicine.CapitalizeFirstLetter();
private static IEnumerable<string> GetWordsThatPointsToType(string[] criteria)
return new string[]{"Receita de Antibióticos", "Receita de Psicotrópicos"};
#endregion Private Methods
#region Overrides of ValueObject
protected override IEnumerable<IComparable> GetEqualityComponents()
public static class DocNameHelper
public const string GrabNameAndExtension = @"(?<fullname>.+?)(\.(?<extension>[^.]*)$|$)";
public const string GrabPartsOfName = @"([\w _<>+;.,']*)*";
public const string GrabDelimiterWithSpaceAround = @"( - )";
public const string GrabFakeDelimiterWithoutAnySpaceAround = @"(?<before>[\d\w' -.]*)(?<=\w)(?<FakeDelimiter>[-˗–])(?=\w)(?<after>[\d\w -.]*)";
public const string TemporarySubstitutionForFakeDelimiter = @"${before}<>${after}";
public const string GrabTemporarySubstitutionForFakeDelimiter = @"(?<before>[\d\w -.]*)(?<=\w)(?<FakeDelimiter>\<\>)(?=\w)(?<after>[\d\w -.]*)";
public const string RestorePreviousStateBeforeFakeDelimiter = @"${before}-${after}";
#endregion Public Constants
internal static string StripOffPart(string partToBeStrippedOff, string partToRemove, string connectorBefore)
if (!string.IsNullOrEmpty(connectorBefore) && !string.IsNullOrWhiteSpace(connectorBefore))
partToRemove = connectorBefore + partToRemove;
if (!string.IsNullOrWhiteSpace(partToRemove))
partToBeStrippedOff = partToBeStrippedOff.Replace(partToRemove.Trim(), string.Empty);
return partToBeStrippedOff = partToBeStrippedOff.Trim();
internal static bool DifficultyToTestPart(string partToTest)
return partToTest.Length > 10 && partToTest.DoesNotContainAnySpace();
internal static Result<string> ReturnResult(string pattern, string part, string groupName, string errorMsg)
_ = GetMatch(pattern, part, groupName, errorMsg, out var result);
internal static Match GetMatch(string pattern, string part, string groupName, string errorMsg, out Result<string> result)
var rgx = new Regex(pattern);
var match = rgx.Match(" " + part.TrimStart());
result = match.Success ? Result.Success(match.Groups[groupName].Value.Trim()) : Result.Failure<string>(errorMsg);
internal static Match GetMatch(string pattern, string part)
var rgx = new Regex(pattern);
var match = rgx.Match(" " + part);
internal static Group GetMatchMainGroup(string pattern, string part)
var rgx = new Regex(pattern);
var match = rgx.Match(part.EnsureOneSingleSpaceAtBegin());
internal static Group GetMatch(string pattern, string part, string groupName)
var rgx = new Regex(pattern);
var match = rgx.Match(part.EnsureOneSingleSpaceAtBegin());
return match.Groups[groupName];
internal static MatchCollection GetMatches(string pattern, string part)
var rgx = new Regex(pattern);
var matches = rgx.Matches(part.EnsureOneSingleSpaceAtBegin());
internal static bool OutOfForbiddenZoneIfSamePart(string groupName, Match match, int startOfForbiddenZone, int endOfForbiddenZone)
return BeforeStartOfForbiddenZone(groupName, match, startOfForbiddenZone) && AfterEndOfForbiddenZone(groupName, match, endOfForbiddenZone);
private static bool BeforeStartOfForbiddenZone(string groupName, Match match, int startOfForbiddenZone)
return match.Groups[groupName].Index + match.Groups[groupName].Length - 1 < startOfForbiddenZone;
private static bool AfterEndOfForbiddenZone(string groupName, Match match, int endOfForbiddenZone)
return match.Groups[groupName].Index > endOfForbiddenZone;
#region Interval and Date
internal static string[] dubiousDDMMOrYYYY() => new[]{"2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012"};
internal static string[] dubiousMMDDOrYYYY() => new[]{""};
#endregion Interval and Date
#region MedicinesAndDosage
#endregion MedicinesAndDosage
internal static bool DateWithNoYearTryParseExact(string dateWithNoYearAndWithoutSpace, out DateTime testDate, CultureInfo cultureInfo, string yearToAssume)
return DateTryParseExact(dateWithNoYearAndWithoutSpace + yearToAssume, out testDate, cultureInfo, string.IsNullOrEmpty(yearToAssume));
internal static bool DateTryParseExact(string dateWithoutSpace, out DateTime testDate, CultureInfo cultureInfo, bool forceDDMM = false)
var yyyy = forceDDMM ? string.Empty : DateFormat.yyyy.GetDescription();
var isDDMM = cultureInfo.Name == "pt-BR";
var ddMMyyyy = isDDMM ? DateFormat.ddMMyyyy.GetDescription() : DateFormat.MMddyyyy.GetDescription();
var ddMMMyyyy = isDDMM ? DateFormat.ddMMMyyyy.GetDescription() : DateFormat.MMMddyyyy.GetDescription();
var ddMMMMyyyy = isDDMM ? DateFormat.ddMMMMyyyy.GetDescription() : DateFormat.MMMMddyyyy.GetDescription();
var ddMM = isDDMM ? DateFormat.ddMM.GetDescription() : DateFormat.MMdd.GetDescription();
var ddMMM = isDDMM ? DateFormat.ddMMM.GetDescription() : DateFormat.MMMdd.GetDescription();
var ddMMMM = isDDMM ? DateFormat.ddMMMM.GetDescription() : DateFormat.MMMMdd.GetDescription();
var ddMMyyyyHHmmssWithSlash = isDDMM ? DateFormat.completeUpToSeconds.GetDescription() : DateFormat.completeUpToSecondsUS.GetDescription();
return DateTime.TryParse(dateWithoutSpace, cultureInfo, DateTimeStyles.None, out testDate) || DateTime.TryParseExact(dateWithoutSpace, yyyy, cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, DateFormat.MMMMyyyy.GetDescription(), cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, DateFormat.MMMyyyy.GetDescription(), cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, DateFormat.MMyyyy.GetDescription(), cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, ddMMyyyy, cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, ddMMMyyyy, cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, ddMMMMyyyy, cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, ddMM, cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, ddMMM, cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, ddMMMM, cultureInfo, DateTimeStyles.AssumeLocal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, ddMMyyyyHHmmssWithSlash, cultureInfo, DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, DateFormat.universalSortable.GetDescription(), cultureInfo, DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal, out testDate) || DateTime.TryParseExact(dateWithoutSpace, DateFormat.sortable.GetDescription(), cultureInfo, DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal, out testDate);
public class WrappedCollection<T> : IList<T>
private readonly IList<T> _list = new List<T>();
public WrappedCollection(IList<T> wrappedCollection)
this._list = wrappedCollection ?? throw new ArgumentNullException(nameof(wrappedCollection));
#region Implementation of IEnumerable
public IEnumerator<T> GetEnumerator()
return _list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
return this.GetEnumerator();
#region Implementation of ICollection<T>
public bool Remove(T item)
return _list.Remove(item);
public bool Contains(T item)
return _list.Contains(item);
public void CopyTo(T[] array, int arrayIndex)
_list.CopyTo(array, arrayIndex);
public int Count => _list.Count;
public bool IsReadOnly => _list.IsReadOnly;
#region Implementation of IList<T>
public int IndexOf(T item)
return _list.IndexOf(item);
public void Insert(int index, T item)
_list.Insert(index, item);
public void RemoveAt(int index)
public T this[int index] { get => _list[index]; set => _list[index] = value; }
public static partial class DateTimeExtensions
public static int YearsBetweenNowAndDate(this DateTime @this) => Math.Abs(DateTime.Now.HowOld(@this, out _, out _));
public static int YearsBetweenDates(this DateTime @this, DateTime that) => Math.Abs(that.HowOld(@this, out _, out _));
public static int HowOld(this DateTime initialDay, DateTime dayToCalculate, out int days, out int months)
months = dayToCalculate.Month - initialDay.Month;
int years = dayToCalculate.Year - initialDay.Year;
if (dayToCalculate.Day < initialDay.Day)
days = (dayToCalculate - initialDay.AddMonths((years * 12) + months)).Days;
public static string HowYearsOldToday(this DateTime birthday, bool allowNegativeAge = false)
var howManyYears = birthday.HowOld(DateTime.Now, out var howManyDays, out var howManyMonths);
if (allowNegativeAge || howManyYears >= 0)
return $"{howManyYears} ano{((howManyYears == 1) ? "" : "s")}";
return "Cannot calculate age";
public static string HowYearsOldAtDate(this DateTime birthday, DateTime atDate, bool allowNegativeAge = false)
var howManyYears = birthday.HowOld(atDate, out var howManyDays, out var howManyMonths);
if (allowNegativeAge || howManyYears >= 0)
return $"{howManyYears} ano{((howManyYears == 1) ? "" : "s")}";
return "Cannot calculate age";
public static string HowYearsMonthsOldToday(this DateTime birthday, bool allowNegativeAge = false)
var howManyYears = birthday.HowOld(DateTime.Now, out var howManyDays, out var howManyMonths);
if (allowNegativeAge || howManyYears >= 0)
return $"{howManyYears} ano{((howManyYears == 1) ? "" : "s")}" + $", {howManyMonths} {((howManyMonths == 1) ? "mês" : "meses")} ";
return "Cannot calculate age";
public static string HowYearsMonthsOldAtDate(this DateTime birthday, DateTime atDate, bool allowNegativeAge = false)
var howManyYears = birthday.HowOld(atDate, out var howManyDays, out var howManyMonths);
if (allowNegativeAge || howManyYears >= 0)
return $"{howManyYears} ano{((howManyYears == 1) ? "" : "s")}" + $", {howManyMonths} {((howManyMonths == 1) ? "mês" : "meses")} ";
return "Cannot calculate age";
public static string HowYearsMonthsDaysOldToday(this DateTime birthday, bool allowNegativeAge = false)
var howManyYears = birthday.HowOld(DateTime.Now, out var howManyDays, out var howManyMonths);
if (allowNegativeAge || howManyYears >= 0)
return $"{howManyYears} ano{((howManyYears == 1) ? "" : "s")}" + $", {howManyMonths} {((howManyMonths == 1) ? "mês" : "meses")} " + $"e {howManyDays} dia{((howManyDays == 1) ? "" : "s")}";
return "Cannot calculate age";
public static string HowYearsMonthsDaysOldAtDatey(this DateTime birthday, DateTime atDate, bool allowNegativeAge = false)
var howManyYears = birthday.HowOld(atDate, out var howManyDays, out var howManyMonths);
if (allowNegativeAge || howManyYears >= 0)
return $"{howManyYears} ano{((howManyYears == 1) ? "" : "s")}" + $", {howManyMonths} {((howManyMonths == 1) ? "mês" : "meses")} " + $"e {howManyDays} dia{((howManyDays == 1) ? "" : "s")}";
return "Cannot calculate age";
public static DateTime MinimumWinFormDateTime(this DateTime @this) => Convert.ToDateTime("1/1/1753 00:00:00");
public static DateTime NullOutlookDateTime(this DateTime @this) => Convert.ToDateTime("1/1/4501 00:00:00");
public static DateTime OutlookDefaultDateForInvalidEntry(this DateTime @this)
if (CultureInfo.CurrentCulture.Name.ToString() == "pt-BR")
return Convert.ToDateTime("30/12/1899 00:00:00");
return Convert.ToDateTime("12/30/1899 00:00:00");
public static DateTime OutlookEarliestDateThatDoesNotProvokeError(this DateTime @this) => Convert.ToDateTime("01/04/1601 00:00:00");
public static DateTime ThisDateOrAppropriateMinimalDateTime(this DateTime @this) => (DateTime)(@this < @this.MinimumWinFormDateTime() || @this == NullOutlookDateTime(@this) ? @this.MinimumWinFormDateTime() : @this);
public static bool IsThisDateNullOrDefault(this DateTime @this) => @this == @this.MinimumWinFormDateTime() || @this == NullOutlookDateTime(@this) || @this == DateTime.MaxValue || @this == DateTime.MinValue || @this == @this.OutlookDefaultDateForInvalidEntry() || @this < @this.OutlookEarliestDateThatDoesNotProvokeError();
public static DateTime ThisDateCandidateOrDateTimeMinimal(this string stringToBeParsed)
DateTime @this = default;
if (stringToBeParsed == null || !DateTime.TryParse(stringToBeParsed, out @this))
return DateTime.MinValue;
public static DateTime ThisDateCandidateOrAppropriateMinimalDateTime(this string stringToBeParsed)
DateTime @this = default;
if (stringToBeParsed == null || !DateTime.TryParse(stringToBeParsed, out @this))
return @this.MinimumWinFormDateTime();
return (DateTime)(@this < @this.MinimumWinFormDateTime() || @this == NullOutlookDateTime(@this) ? @this.MinimumWinFormDateTime() : @this);
public static DateTime ReturnAnteriorBetweenDates(this DateTime d1, DateTime d2) => d1 < d2 ? d1 : d2;
public static DateTime ReturnPosteriorBetweenDates(this DateTime d1, DateTime d2) => d1 < d2 ? d1 : d2;
public static DateTime AllowPastOrNowTimeButNotFuture(this DateTime? ToTest, DateTime? ToCompare = null)
ToCompare = DateTime.Now;
var value when value == null => DateTime.Now,
var value when value < ToCompare => (DateTime)ToTest,
var value when value > ToCompare => throw new ArgumentOutOfRangeException("Date cannot be in the future..."),
public static DateTime AllowOnlyFuture(this DateTime? ToTest, double numberOfHoursToAdd = 1, DateTime? ToCompare = null)
ToCompare = DateTime.Now;
var value when value == null => DateTime.Now.AddHours(numberOfHoursToAdd),
var value when value > ToCompare => (DateTime)ToTest,
var value when value < ToCompare => throw new ArgumentOutOfRangeException("Date cannot be in the past or even now..."),
public static class StringTextExtensions
private const char OneBlankSpace = ' ';
public static string RemoveUnnecessarySpaces(this string textToTrim)
return Regex.Replace(textToTrim, @"\s+", " ").Trim();
public static string RemoveAllSpaces(this string textToTrim)
return textToTrim.Replace(" ", string.Empty);
public static string RemoveAllPunctuation(this string textToTrim)
return new string (textToTrim.Where(c => !char.IsPunctuation(c)).Where(c => !char.IsSymbol(c)).ToArray());
public static string GetRidOfNonLetterCharsInKeyOrPairElements(this string rawString) => rawString.RemoveAllPunctuation().RemoveAllSpaces().RemoveBrackets();
public static string GetNumberOfCharsJustBeforeSubstring(this string text, string beforeThis, int numberOfChars = 1)
var txtBefore = text.GetUntilOrEmpty(beforeThis);
return text.GetUntilOrEmpty(beforeThis).Substring(txtBefore.Length - numberOfChars);
Console.WriteLine(ex.Message);
public static string GetUntilOrEmpty(this string text, string stopAt = "-")
if (!string.IsNullOrWhiteSpace(text))
int charLocation = text.IndexOf(stopAt, StringComparison.Ordinal);
return text.Substring(0, charLocation);
public static string GetAfterOrEmpty(this string text, string stopAt = "-")
if (!string.IsNullOrWhiteSpace(text))
int charLocation = text.IndexOf(stopAt, StringComparison.Ordinal);
return text.Substring(charLocation + stopAt.Length, text.Length - charLocation - stopAt.Length);
public static string GetMiddleString(this string inputString, char separator = OneBlankSpace)
var input = inputString.Split(separator);
var firstToken = input[0];
var lastToken = input[input.Length - 1];
var pos1 = inputString.IndexOf(firstToken) + firstToken.Length;
var pos2 = inputString.IndexOf(lastToken);
var result = inputString.Substring(pos1, pos2 - pos1).Trim() ?? string.Empty;
public static (string textBefore, string textAfter) GetTextBeforeAndAfterSubstring(this string textToExtract, string stringToSearchFor, int desiredLengthToCut, int indexToSearchedString)
var textBefore = textToExtract.Substring(indexToSearchedString - desiredLengthToCut < 0 ? 0 : indexToSearchedString - desiredLengthToCut, indexToSearchedString - desiredLengthToCut > 0 ? desiredLengthToCut : indexToSearchedString);
var textAfter = textToExtract.Substring(indexToSearchedString + stringToSearchFor.Length, DecideHowMuchItCanCutAfter(textToExtract.Length, indexToSearchedString + stringToSearchFor.Length, desiredLengthToCut));
return (textBefore, textAfter);
static int DecideHowMuchItCanCutAfter(int totalLength, int beginCut, int lengthToCut)
if (beginCut + lengthToCut < totalLength)
if (beginCut + lengthToCut >= totalLength)
return totalLength - beginCut;
public static string RemoveDiacritics(this string s)
string normalizedString = s.Normalize(NormalizationForm.FormD);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < normalizedString.Length; i++)
char c = normalizedString[i];
if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
return stringBuilder.ToString();
public static string RemoveBrackets(this string s)
return s.Replace("[", string.Empty).Replace("]", string.Empty);
public static string SurroundWithDoubleQuotes(this string text)
return SurroundWith(text, "\"");
public static string SurroundWith(this string text, string ends)
return ends + text + ends;
public static string EscapeSingleQuote(this string text)
return text.Replace("'", @"\'");
public static string AddSingleQuoteAsEscapeCharacter(this string text)
return text.Replace("'", @"''");
public static string EnsureOneSingleSpaceAtBegin(this string text)
return OneBlankSpace + text.TrimStart();
public static string CapitalizeFirstLetter(this string value)
char[] array = value.ToCharArray();
if (char.IsLower(array[0]))
array[0] = char.ToUpper(array[0]);
for (int i = 1; i < array.Length; i++)
if (char.IsLower(array[i]))
array[i] = char.ToUpper(array[i]);
return new string (array);
public static string SplitCapitalizedWords(this string source)
if (String.IsNullOrEmpty(source))
var newText = new StringBuilder(source.Length * 2);
newText.Append(source[0]);
for (int i = 1; i < source.Length; i++)
if (char.IsUpper(source[i]))
newText.Append(source[i]);
return newText.ToString();
public static string TrimLastCharacter(this String str) => String.IsNullOrEmpty(str) ? str : str.TrimEnd(str[str.Length - 1]);
public static IEnumerable<int> AllIndexesOf(this string str, string searchString)
int minIndex = str.IndexOf(searchString, StringComparison.Ordinal);
minIndex = str.IndexOf(searchString, minIndex + searchString.Length, StringComparison.Ordinal);
public static bool ContainsAny(this string @this, params string[] values)
foreach (string value in values)
if (@this.IndexOf(value) != -1)
public static bool ContainsAny(this string @this, StringComparison comparisonType, params string[] values)
foreach (string value in values)
if (@this.IndexOf(value, comparisonType) != -1)
public static bool DoesNotContainAnySpace(this string @this) => !@this.Any(char.IsWhiteSpace);
public static bool ContainsOnly(this string @this, string allowedChars) => @this.All(allowedChars.Contains);
public static bool StringHasOnlyNumbers(this string @this) => @this.ReturnOnlyNumbers().Length == @this.Length;
public static List<string> ReturnOnlyInvalidChars(this string @this, string allowedChars) => (
where !allowedChars.Contains(c.ToString())select c.ToString()).ToList();
public static string ReturnOnlyNumbers(this string @this) => new(@this.Where(char.IsDigit).ToArray());
public static int? ReturnOnlyNumbersAsInt(this string @this)
int.TryParse(@this.ReturnOnlyNumbers(), out var result);
public static string ReturnOnlyNonNumericCharacters(this string @this) => Regex.Replace(@this, @"[\d-]", string.Empty);
public static int[] ReturnOnlyNumbersToArray(this string @this) => Regex.Matches(@this, "(-?[0-9]+)").OfType<Match>().Select(m => int.Parse(m.Value)).ToArray();
public static int GetSingleDigitAtPositionInFilteredStrOnlyNumbers(this string @this, int position1Based)
if (position1Based < 1 || position1Based > @this.Length - 1)
throw new ArgumentOutOfRangeException(nameof(position1Based), $"{nameof(position1Based)} cannot be outer of string limits");
return int.Parse(@this.ReturnOnlyNumbers()[position1Based - 1].ToString());
public static string FormatPhoneNumber(this long number, string mask) => number.ToString(mask);
public static string FormatPhoneNumber(this string number)
var mask = number.ReturnOnlyNumbers().Length switch
15 => @"0 000 (00) 00000-0000",
13 => @"+00 (00) 00000-0000",
11 => @"(00) 00000-0000",
_ => throw new ArgumentOutOfRangeException(nameof(FormatPhoneNumber), "FormatPhoneNumber only accepts certain ranges of phone numbers"),
return long.Parse(number.ReturnOnlyNumbers()).FormatPhoneNumber(mask);
public static bool IsDate(this string @this, out DateTime date) => DateTime.TryParse(@this, out date);
public static bool IsDate(this string @this) => DateTime.TryParse(@this, out var date);
public static bool IsNumber(this string @this) => int.TryParse(@this, out var number);
public static bool IsDigit(this string @this) => @this.All(c => c >= '0' && c <= '9');
public static class EasyOfficeFolderExtensions
public static string GetParentFolder(this string pathSource)
return Path.GetFullPath(Path.Combine(pathSource, @"..\"));
public static string CombinePaths(this string pathWithRoot, string pathDistal)
var networkFolder = !pathWithRoot.Contains(":");
var pathOne = pathWithRoot.Split(@"\".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var pathTwo = pathDistal.Split(@"\".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var pathFinal = pathOne.Concat(pathTwo);
var preFinalPath = Path.Combine(pathFinal.ToArray());
return "\\\\" + preFinalPath;
return preFinalPath.Contains(":\\") ? preFinalPath : preFinalPath.Replace(":", ":\\");
public static class ObjectTextExtensions
public static T ObjToEnum<T>(this object o, int unknown = 0)
T enumVal = (T)Enum.Parse(typeof(T), o.ToString());
return (T)Enum.ToObject(typeof(T), unknown);
return (T)Enum.ToObject(typeof(T), unknown);
public static bool IsDefined(this System.Enum value)
return Enum.IsDefined(value.GetType(), value);
public static int EnumToInt<TValue>(this TValue value)
where TValue : System.Enum => (int)(object)value;
public static TValue IntToEnum<TValue>(this int value)
where TValue : System.Enum => (TValue)(object)value;
public static T GetEnumValue<T>(this string value)
throw new Exception("T must be an enum");
if (Enum.IsDefined(t, value))
return (T)Enum.Parse(t, value);
public static T GetValueFromDescription<T>(this string description, bool throwException = true)
foreach (var field in typeof(T).GetFields())
if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))is DescriptionAttribute attribute)
if (attribute.Description == description)
return (T)field.GetValue(null);
if (field.Name == description)
return (T)field.GetValue(null);
throw new ArgumentException("Not found.", nameof(description));
public static string GetDescription(this Enum value)
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
public static string GetDescription(this object e, Type enumType)
var fieldValue = enumType.GetField(Enum.GetValues(enumType).Cast<object>().Where(o => o.ToString() == e.ToString()).Select(o => o.ToString()).FirstOrDefault()).ToString();
FieldInfo field = enumType.GetField(fieldValue.Contains(" ") ? fieldValue.Split().Last() : fieldValue);
DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? e.ToString() : attribute.Description;
public static Dictionary<int, TValue> EnumToDictionary<TValue>(this TValue value)
where TValue : System.Enum
Type enumType = typeof(TValue);
var allEnumValues = enumType.GetEnumValues().Cast<TValue>();
var enumDL = new Dictionary<int, TValue>();
foreach (TValue val in allEnumValues.ToList())
enumDL.Add(val.EnumToInt(), val);
public static Dictionary<int, Enum> EnumToDictionaryNotGeneric(this Enum @enum)
Type enumType = @enum.GetType();
var allEnumValues = Enum.GetValues(@enum.GetType()).Cast<Enum>();
var enumDL = new Dictionary<int, Enum>();
foreach (var val in allEnumValues.ToList())
enumDL.Add(val.EnumToInt(), val);
public static Dictionary<int, T> EnumToDictionary<T>(this Type enumType)
var allEnumValues = enumType.GetEnumValues().Cast<T>();
var converter = new EnumConverter(enumType);
var enumDL = new Dictionary<int, T>();
foreach (T val in allEnumValues.ToList())
enumDL.Add(val.EnumToInt(), val);
public static IReadOnlyList<T> GetValues<T>()
return (T[])Enum.GetValues(typeof(T));