Skip to content

Commit 71c7bca

Browse files
committed
Move parse code into UnitParser
DRY up the unit class code a bit.
1 parent d17c02e commit 71c7bca

38 files changed

+383
-2775
lines changed

UnitsNet/CustomCode/UnitParser.cs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright(c) 2007 Andreas Gullberg Larsen
2+
// https://github.com/anjdreas/UnitsNet
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in
12+
// all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
// THE SOFTWARE.
21+
22+
using System;
23+
using System.Collections.Generic;
24+
using System.Diagnostics.CodeAnalysis;
25+
using System.Globalization;
26+
using System.Linq;
27+
using System.Text.RegularExpressions;
28+
using JetBrains.Annotations;
29+
30+
namespace UnitsNet
31+
{
32+
internal delegate TUnit ParseUnit<out TUnit>(string value, string unit, IFormatProvider formatProvider = null);
33+
34+
internal static class UnitParser
35+
{
36+
[SuppressMessage("ReSharper", "UseStringInterpolation")]
37+
internal static TUnit ParseUnit<TUnit>([NotNull] string str,
38+
[CanBeNull] IFormatProvider formatProvider,
39+
[NotNull] ParseUnit<TUnit> parseUnit,
40+
[NotNull] Func<TUnit, TUnit, TUnit> add)
41+
{
42+
if (str == null) throw new ArgumentNullException(nameof(str));
43+
if (parseUnit == null) throw new ArgumentNullException(nameof(parseUnit));
44+
if (add == null) throw new ArgumentNullException(nameof(add));
45+
46+
var numFormat = formatProvider != null
47+
? (NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo))
48+
: NumberFormatInfo.CurrentInfo;
49+
50+
string numRegex = string.Format(@"[\d., {0}{1}]*\d",
51+
// allows digits, dots, commas, and spaces in the quantity (must end in digit)
52+
numFormat.NumberGroupSeparator, // adds provided (or current) culture's group separator
53+
numFormat.NumberDecimalSeparator); // adds provided (or current) culture's decimal separator
54+
55+
const string exponentialRegex = @"(?:[eE][-+]?\d+)?)";
56+
57+
string regexString = string.Format(@"(?:\s*(?<value>[-+]?{0}{1}{2}{3})?{4}{5}",
58+
numRegex, // capture base (integral) Quantity value
59+
exponentialRegex, // capture exponential (if any), end of Quantity capturing
60+
@"\s?", // ignore whitespace (allows both "1kg", "1 kg")
61+
@"(?<unit>[^\s\d,]+)", // capture Unit (non-whitespace) input
62+
@"(and)?,?", // allow "and" & "," separators between quantities
63+
@"(?<invalid>[a-z]*)?"); // capture invalid input
64+
65+
List<TUnit> quantities = ParseWithRegex(regexString, str, parseUnit, formatProvider);
66+
if (quantities.Count == 0)
67+
{
68+
throw new ArgumentException(
69+
"Expected string to have at least one pair of quantity and unit in the format"
70+
+ " \"&lt;quantity&gt; &lt;unit&gt;\". Eg. \"5.5 m\" or \"1ft 2in\"");
71+
}
72+
return quantities.Aggregate(add);
73+
}
74+
75+
/// <summary>
76+
/// Parse a string given a particular regular expression.
77+
/// </summary>
78+
/// <exception cref="UnitsNetException">Error parsing string.</exception>
79+
private static List<TUnit> ParseWithRegex<TUnit>(string regexString, string str, ParseUnit<TUnit> parseUnit,
80+
IFormatProvider formatProvider = null)
81+
{
82+
var regex = new Regex(regexString);
83+
MatchCollection matches = regex.Matches(str.Trim());
84+
var converted = new List<TUnit>();
85+
86+
foreach (Match match in matches)
87+
{
88+
GroupCollection groups = match.Groups;
89+
90+
var valueString = groups["value"].Value;
91+
var unitString = groups["unit"].Value;
92+
if (groups["invalid"].Value != "")
93+
{
94+
var newEx = new UnitsNetException("Invalid string detected: " + groups["invalid"].Value);
95+
newEx.Data["input"] = str;
96+
newEx.Data["matched value"] = valueString;
97+
newEx.Data["matched unit"] = unitString;
98+
newEx.Data["formatprovider"] = formatProvider?.ToString();
99+
throw newEx;
100+
}
101+
if (valueString == "" && unitString == "") continue;
102+
103+
try
104+
{
105+
converted.Add(parseUnit(valueString, unitString, formatProvider));
106+
}
107+
catch (AmbiguousUnitParseException)
108+
{
109+
throw;
110+
}
111+
catch (Exception ex)
112+
{
113+
var newEx = new UnitsNetException("Error parsing string.", ex);
114+
newEx.Data["input"] = str;
115+
newEx.Data["matched value"] = valueString;
116+
newEx.Data["matched unit"] = unitString;
117+
newEx.Data["formatprovider"] = formatProvider?.ToString();
118+
throw newEx;
119+
}
120+
}
121+
return converted;
122+
}
123+
}
124+
}

UnitsNet/GeneratedCode/UnitClasses/Acceleration.g.cs

Lines changed: 7 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2007 Andreas Gullberg Larsen ([email protected]).
1+
// Copyright © 2007 Andreas Gullberg Larsen ([email protected]).
22
// https://github.com/anjdreas/UnitsNet
33
//
44
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -618,81 +618,13 @@ public static Acceleration Parse(string str, [CanBeNull] Culture culture)
618618
#else
619619
IFormatProvider formatProvider = culture;
620620
#endif
621-
var numFormat = formatProvider != null ?
622-
(NumberFormatInfo) formatProvider.GetFormat(typeof (NumberFormatInfo)) :
623-
NumberFormatInfo.CurrentInfo;
624-
625-
var numRegex = string.Format(@"[\d., {0}{1}]*\d", // allows digits, dots, commas, and spaces in the quantity (must end in digit)
626-
numFormat.NumberGroupSeparator, // adds provided (or current) culture's group separator
627-
numFormat.NumberDecimalSeparator); // adds provided (or current) culture's decimal separator
628-
var exponentialRegex = @"(?:[eE][-+]?\d+)?)";
629-
var regexString = string.Format(@"(?:\s*(?<value>[-+]?{0}{1}{2}{3})?{4}{5}",
630-
numRegex, // capture base (integral) Quantity value
631-
exponentialRegex, // capture exponential (if any), end of Quantity capturing
632-
@"\s?", // ignore whitespace (allows both "1kg", "1 kg")
633-
@"(?<unit>[^\s\d,]+)", // capture Unit (non-whitespace) input
634-
@"(and)?,?", // allow "and" & "," separators between quantities
635-
@"(?<invalid>[a-z]*)?"); // capture invalid input
636-
637-
var quantities = ParseWithRegex(regexString, str, formatProvider);
638-
if (quantities.Count == 0)
639-
{
640-
throw new ArgumentException(
641-
"Expected string to have at least one pair of quantity and unit in the format"
642-
+ " \"&lt;quantity&gt; &lt;unit&gt;\". Eg. \"5.5 m\" or \"1ft 2in\"");
643-
}
644-
return quantities.Aggregate((x, y) => Acceleration.FromMeterPerSecondSquared(x.MeterPerSecondSquared + y.MeterPerSecondSquared));
645-
}
646-
647-
/// <summary>
648-
/// Parse a string given a particular regular expression.
649-
/// </summary>
650-
/// <exception cref="UnitsNetException">Error parsing string.</exception>
651-
private static List<Acceleration> ParseWithRegex(string regexString, string str, IFormatProvider formatProvider = null)
652-
{
653-
var regex = new Regex(regexString);
654-
MatchCollection matches = regex.Matches(str.Trim());
655-
var converted = new List<Acceleration>();
656-
657-
foreach (Match match in matches)
658-
{
659-
GroupCollection groups = match.Groups;
660-
661-
var valueString = groups["value"].Value;
662-
var unitString = groups["unit"].Value;
663-
if (groups["invalid"].Value != "")
664-
{
665-
var newEx = new UnitsNetException("Invalid string detected: " + groups["invalid"].Value);
666-
newEx.Data["input"] = str;
667-
newEx.Data["matched value"] = valueString;
668-
newEx.Data["matched unit"] = unitString;
669-
newEx.Data["formatprovider"] = formatProvider == null ? null : formatProvider.ToString();
670-
throw newEx;
671-
}
672-
if (valueString == "" && unitString == "") continue;
673-
674-
try
621+
return UnitParser.ParseUnit<Acceleration>(str, formatProvider,
622+
delegate(string value, string unit, IFormatProvider formatProvider2)
675623
{
676-
AccelerationUnit unit = ParseUnit(unitString, formatProvider);
677-
double value = double.Parse(valueString, formatProvider);
678-
679-
converted.Add(From(value, unit));
680-
}
681-
catch(AmbiguousUnitParseException)
682-
{
683-
throw;
684-
}
685-
catch(Exception ex)
686-
{
687-
var newEx = new UnitsNetException("Error parsing string.", ex);
688-
newEx.Data["input"] = str;
689-
newEx.Data["matched value"] = valueString;
690-
newEx.Data["matched unit"] = unitString;
691-
newEx.Data["formatprovider"] = formatProvider == null ? null : formatProvider.ToString();
692-
throw newEx;
693-
}
694-
}
695-
return converted;
624+
double parsedValue = double.Parse(value, formatProvider2);
625+
AccelerationUnit parsedUnit = ParseUnit(unit, formatProvider2);
626+
return From(parsedValue, parsedUnit);
627+
}, (x, y) => FromMeterPerSecondSquared(x.MeterPerSecondSquared + y.MeterPerSecondSquared));
696628
}
697629

698630
/// <summary>

UnitsNet/GeneratedCode/UnitClasses/AmplitudeRatio.g.cs

Lines changed: 7 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2007 Andreas Gullberg Larsen ([email protected]).
1+
// Copyright © 2007 Andreas Gullberg Larsen ([email protected]).
22
// https://github.com/anjdreas/UnitsNet
33
//
44
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -478,81 +478,13 @@ public static AmplitudeRatio Parse(string str, [CanBeNull] Culture culture)
478478
#else
479479
IFormatProvider formatProvider = culture;
480480
#endif
481-
var numFormat = formatProvider != null ?
482-
(NumberFormatInfo) formatProvider.GetFormat(typeof (NumberFormatInfo)) :
483-
NumberFormatInfo.CurrentInfo;
484-
485-
var numRegex = string.Format(@"[\d., {0}{1}]*\d", // allows digits, dots, commas, and spaces in the quantity (must end in digit)
486-
numFormat.NumberGroupSeparator, // adds provided (or current) culture's group separator
487-
numFormat.NumberDecimalSeparator); // adds provided (or current) culture's decimal separator
488-
var exponentialRegex = @"(?:[eE][-+]?\d+)?)";
489-
var regexString = string.Format(@"(?:\s*(?<value>[-+]?{0}{1}{2}{3})?{4}{5}",
490-
numRegex, // capture base (integral) Quantity value
491-
exponentialRegex, // capture exponential (if any), end of Quantity capturing
492-
@"\s?", // ignore whitespace (allows both "1kg", "1 kg")
493-
@"(?<unit>[^\s\d,]+)", // capture Unit (non-whitespace) input
494-
@"(and)?,?", // allow "and" & "," separators between quantities
495-
@"(?<invalid>[a-z]*)?"); // capture invalid input
496-
497-
var quantities = ParseWithRegex(regexString, str, formatProvider);
498-
if (quantities.Count == 0)
499-
{
500-
throw new ArgumentException(
501-
"Expected string to have at least one pair of quantity and unit in the format"
502-
+ " \"&lt;quantity&gt; &lt;unit&gt;\". Eg. \"5.5 m\" or \"1ft 2in\"");
503-
}
504-
return quantities.Aggregate((x, y) => AmplitudeRatio.FromDecibelVolts(x.DecibelVolts + y.DecibelVolts));
505-
}
506-
507-
/// <summary>
508-
/// Parse a string given a particular regular expression.
509-
/// </summary>
510-
/// <exception cref="UnitsNetException">Error parsing string.</exception>
511-
private static List<AmplitudeRatio> ParseWithRegex(string regexString, string str, IFormatProvider formatProvider = null)
512-
{
513-
var regex = new Regex(regexString);
514-
MatchCollection matches = regex.Matches(str.Trim());
515-
var converted = new List<AmplitudeRatio>();
516-
517-
foreach (Match match in matches)
518-
{
519-
GroupCollection groups = match.Groups;
520-
521-
var valueString = groups["value"].Value;
522-
var unitString = groups["unit"].Value;
523-
if (groups["invalid"].Value != "")
524-
{
525-
var newEx = new UnitsNetException("Invalid string detected: " + groups["invalid"].Value);
526-
newEx.Data["input"] = str;
527-
newEx.Data["matched value"] = valueString;
528-
newEx.Data["matched unit"] = unitString;
529-
newEx.Data["formatprovider"] = formatProvider == null ? null : formatProvider.ToString();
530-
throw newEx;
531-
}
532-
if (valueString == "" && unitString == "") continue;
533-
534-
try
481+
return UnitParser.ParseUnit<AmplitudeRatio>(str, formatProvider,
482+
delegate(string value, string unit, IFormatProvider formatProvider2)
535483
{
536-
AmplitudeRatioUnit unit = ParseUnit(unitString, formatProvider);
537-
double value = double.Parse(valueString, formatProvider);
538-
539-
converted.Add(From(value, unit));
540-
}
541-
catch(AmbiguousUnitParseException)
542-
{
543-
throw;
544-
}
545-
catch(Exception ex)
546-
{
547-
var newEx = new UnitsNetException("Error parsing string.", ex);
548-
newEx.Data["input"] = str;
549-
newEx.Data["matched value"] = valueString;
550-
newEx.Data["matched unit"] = unitString;
551-
newEx.Data["formatprovider"] = formatProvider == null ? null : formatProvider.ToString();
552-
throw newEx;
553-
}
554-
}
555-
return converted;
484+
double parsedValue = double.Parse(value, formatProvider2);
485+
AmplitudeRatioUnit parsedUnit = ParseUnit(unit, formatProvider2);
486+
return From(parsedValue, parsedUnit);
487+
}, (x, y) => FromDecibelVolts(x.DecibelVolts + y.DecibelVolts));
556488
}
557489

558490
/// <summary>

0 commit comments

Comments
 (0)