mirror of
https://github.com/oliverbooth/X10D
synced 2024-11-10 03:45:41 +00:00
Refactor TimeSpanParse.Parse to .TryParse
Exception will no longer be thrown
This commit is contained in:
parent
27a370cffe
commit
a8de6e1755
@ -414,20 +414,21 @@ namespace X10D.StringExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses a shorthand time span string (e.g. 3w 2d 1.5h) and converts it to an instance of
|
/// Parses a shorthand time span string (e.g. 3w 2d 1.5h) and converts it to an instance of <see cref="TimeSpan" />.
|
||||||
/// <see cref="TimeSpan" />.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str">The input string.</param>
|
/// <param name="input">The input string.</param>
|
||||||
/// <returns>Returns an instance of <see cref="TimeSpan" />.</returns>
|
/// <returns>Returns an instance of <see cref="TimeSpan" />.</returns>
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="str" /> is <see langword="null" />.</exception>
|
/// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null" />.</exception>
|
||||||
public static TimeSpan ToTimeSpan(this string str)
|
public static TimeSpan ToTimeSpan(this string input)
|
||||||
{
|
{
|
||||||
if (str is null)
|
if (input is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(str));
|
throw new ArgumentNullException(nameof(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
return TimeSpanParser.Parse(str);
|
return TimeSpanParser.TryParse(input, out var result)
|
||||||
|
? result
|
||||||
|
: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace X10D
|
namespace X10D
|
||||||
@ -9,69 +9,96 @@ namespace X10D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class TimeSpanParser
|
public static class TimeSpanParser
|
||||||
{
|
{
|
||||||
|
private const string RealNumberPattern = @"(\d*\.\d+|\d+)";
|
||||||
|
|
||||||
|
private static readonly string Pattern = $"^(?:{RealNumberPattern} *y)? *" +
|
||||||
|
$"^(?:{RealNumberPattern} *mo)? *" +
|
||||||
|
$"^(?:{RealNumberPattern} *w)? *" +
|
||||||
|
$"(?:{RealNumberPattern} *d)? *" +
|
||||||
|
$"(?:{RealNumberPattern} *h)? *" +
|
||||||
|
$"(?:{RealNumberPattern} *m)? *" +
|
||||||
|
$"(?:{RealNumberPattern} *s)? *" +
|
||||||
|
$"(?:{RealNumberPattern} *ms)?$";
|
||||||
|
|
||||||
|
private static readonly Regex Regex = new(Pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses a shorthand time span string (e.g. 3w 2d 1.5h) and converts it to an instance of <see cref="TimeSpan" />
|
/// Attempts to parses a shorthand time span string (e.g. 3w 2d 1.5h), converting it to an instance of
|
||||||
/// which represents that duration of time.
|
/// <see cref="TimeSpan" /> which represents that duration of time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">The input string.</param>
|
/// <param name="input">The input string.</param>
|
||||||
|
/// <param name="result">The parsed result.</param>
|
||||||
/// <param name="provider">The format provider.</param>
|
/// <param name="provider">The format provider.</param>
|
||||||
/// <returns>An instance of <see cref="TimeSpan" /> constructed from the parsed <paramref name="input" />.</returns>
|
/// <returns><see langword="true" /> if the parse was successful, <see langword="false" /> otherwise.</returns>
|
||||||
public static TimeSpan Parse(string input, IFormatProvider? provider = null)
|
public static bool TryParse(string input, out TimeSpan result, IFormatProvider? provider = null)
|
||||||
{
|
{
|
||||||
const string realNumberPattern = @"([0-9]*\.[0-9]+|[0-9]+)";
|
result = default;
|
||||||
var pattern = $"^(?:{realNumberPattern} *w)? *" +
|
|
||||||
$"(?:{realNumberPattern} *d)? *" +
|
|
||||||
$"(?:{realNumberPattern} *h)? *" +
|
|
||||||
$"(?:{realNumberPattern} *m)? *" +
|
|
||||||
$"(?:{realNumberPattern} *s)? *" +
|
|
||||||
$"(?:{realNumberPattern} *ms)?$";
|
|
||||||
|
|
||||||
var match = Regex.Match(input, pattern);
|
var match = Regex.Match(input);
|
||||||
double weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
|
|
||||||
|
|
||||||
if (match.Groups[1].Success)
|
if (!match.Success)
|
||||||
{
|
{
|
||||||
weeks = double.Parse(match.Groups[1].Value, provider);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups[2].Success)
|
bool TryParseAt(int group, out double parsedResult)
|
||||||
{
|
{
|
||||||
days = double.Parse(match.Groups[2].Value, provider);
|
parsedResult = 0;
|
||||||
|
|
||||||
|
return match.Groups[@group].Success
|
||||||
|
&& double.TryParse(match.Groups[@group].Value, NumberStyles.Number, provider, out parsedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups[3].Success)
|
if (!TryParseAt(1, out var years))
|
||||||
{
|
{
|
||||||
hours = double.Parse(match.Groups[3].Value, provider);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups[4].Success)
|
if (!TryParseAt(2, out var months))
|
||||||
{
|
{
|
||||||
minutes = double.Parse(match.Groups[4].Value, provider);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups[5].Success)
|
if (!TryParseAt(3, out var weeks))
|
||||||
{
|
{
|
||||||
seconds = double.Parse(match.Groups[5].Value, provider);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups[6].Success)
|
if (!TryParseAt(4, out var days))
|
||||||
{
|
{
|
||||||
milliseconds = double.Parse(match.Groups[6].Value, provider);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trace.WriteLine($"Input: {input}");
|
if (!TryParseAt(5, out var hours))
|
||||||
Trace.WriteLine($"Parsed: {weeks}w {days}d {hours}h {minutes}m {seconds}s {milliseconds}ms");
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var span = TimeSpan.Zero;
|
if (!TryParseAt(6, out var minutes))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
span += TimeSpan.FromDays(weeks * 7);
|
if (!TryParseAt(7, out var seconds))
|
||||||
span += TimeSpan.FromDays(days);
|
{
|
||||||
span += TimeSpan.FromHours(hours);
|
return false;
|
||||||
span += TimeSpan.FromMinutes(minutes);
|
}
|
||||||
span += TimeSpan.FromSeconds(seconds);
|
|
||||||
span += TimeSpan.FromMilliseconds(milliseconds);
|
|
||||||
|
|
||||||
return span;
|
if (!TryParseAt(8, out var milliseconds))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += TimeSpan.FromDays(years * 365);
|
||||||
|
result += TimeSpan.FromDays(months * 30);
|
||||||
|
result += TimeSpan.FromDays(weeks * 7);
|
||||||
|
result += TimeSpan.FromDays(days);
|
||||||
|
result += TimeSpan.FromHours(hours);
|
||||||
|
result += TimeSpan.FromMinutes(minutes);
|
||||||
|
result += TimeSpan.FromSeconds(seconds);
|
||||||
|
result += TimeSpan.FromMilliseconds(milliseconds);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user