private void AdjustForShortenedRange(Tuple <string, string> input, ArchiveDate date, bool dmy, DateMonthStyle monthStyle) { // if no match for Min/Max but we're inside a range, // try with shortened ranges // DMY can shorten Min if (dmy) { AdjustDmyForShortenedRange(input, date, monthStyle); } else { AdjustYmdForShortenedRange(input, date, monthStyle); } }
/// <summary> /// Parses the specified text, representing one or more dates or dates /// ranges. /// </summary> /// <param name="text">The text.</param> /// <returns>date(s) parsed</returns> /// <exception cref="ArgumentNullException">null text</exception> public IList <ArchiveDate> Parse(string text) { if (text == null) { throw new ArgumentNullException(nameof(text)); } // split at `;` (TODO: prefilter to replace `,` as ranges // separator with `;`) DateMonthStyle monthStyle = DateMonthStyle.Undefined; char ymdSep = '\0'; List <ArchiveDate> dates = new List <ArchiveDate>(); // several dates (or dates ranges) are separated by ; foreach (string part in text.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { // remove [ ] to simplify styles detection string purgedPart = _squaresRegex.Replace(part, ""); // detect month style (unless already detected in another part) if (monthStyle == DateMonthStyle.Undefined) { monthStyle = DetectMonthStyle(purgedPart); } // detect numeric M style (unless already detected in another part) if ((monthStyle == DateMonthStyle.Numeric || monthStyle == DateMonthStyle.Undefined) && ymdSep == '\0') { ymdSep = DetectYmdSeparator(purgedPart); } // detect YMD order bool dmy = _dmyRegex.IsMatch(purgedPart) || _dmyNamedRegex.IsMatch(purgedPart); // split range pair if any var t = SplitRange(part, ymdSep); if (t != null) { ArchiveDate date = new ArchiveDate { A = ParsePoint(t.Item1, dmy, monthStyle), B = ParsePoint(t.Item2, dmy, monthStyle) }; // corner case: shortened ranges AdjustForShortenedRange(t, date, dmy, monthStyle); dates.Add(date); } // rng else { // ante/post can appear only before single-point dates string pointText = part; Match m = _antePostRegex.Match(part); bool min = true, max = true; if (m.Success) { pointText = part.Substring(m.Length); if (string.Equals(m.Groups[1].Value, "ante", StringComparison.InvariantCultureIgnoreCase)) { min = false; } else { max = false; } } ArchiveDatePoint point = ParsePoint(pointText, dmy, monthStyle); if (point != null) { ArchiveDate date = new ArchiveDate(); if (min && max) { date.A = point; date.B = point.Clone(); } else { if (min) { date.A = point; } else { date.B = point; } } dates.Add(date); } } // !rng } return(dates); }
private void AdjustDmyForShortenedRange(Tuple <string, string> input, ArchiveDate date, DateMonthStyle monthStyle) { if (date.A != null || date.B?.ValueType != DateValueType.Year || date.B.Month == 0) { return; } int i = (int)(monthStyle == 0 ? 0 : monthStyle - 1); Match match = _shortenedDmyRegexes[i].Match(input.Item1); if (match.Success) { // copy YM from Max date.A = new ArchiveDatePoint { ValueType = DateValueType.Year, Value = date.B.Value, IsYearInferred = date.B.IsYearInferred, Month = date.B.Month, IsMonthInferred = date.B.IsMonthInferred }; // style N has groups d/m or md if (i == 0) { if (match.Groups["md"].Length > 0) { if (date.B.Day > 0) { date.A.Day = short.Parse(match.Groups["md"].Value, CultureInfo.InvariantCulture); } else { date.A.Month = short.Parse(match.Groups["md"].Value, CultureInfo.InvariantCulture); } } else { date.A.Month = short.Parse(match.Groups["m"].Value, CultureInfo.InvariantCulture); date.A.Day = short.Parse(match.Groups["d"].Value, CultureInfo.InvariantCulture); } } // N else { // styles S/F have groups m/d if (match.Groups["m"].Length > 0) { YmdToken m = YmdToken.Parse(match.Groups["m"].Value, 'm'); date.A.Month = m.Value; } if (match.Groups["d"].Length > 0) { YmdToken d = YmdToken.Parse(match.Groups["d"].Value, 'd'); date.A.Day = d.Value; } } // !N } }