-
Notifications
You must be signed in to change notification settings - Fork 394
Bugfix/parse mapped abbrev #265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
2e78d20
fdd4335
bead97e
13c9931
d6b1ac4
96dede1
3a65835
c109cc9
2b8fdf9
1744ce1
6fa99ed
e6117cd
922e71a
ee3e16e
c1318b5
3f434da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,15 +29,15 @@ | |
|
||
namespace UnitsNet | ||
{ | ||
internal delegate TUnit ParseUnit<out TUnit>(string value, string unit, IFormatProvider formatProvider = null); | ||
internal delegate TQuantity ParseUnit<out TQuantity>(string value, string unit, IFormatProvider formatProvider = null); | ||
|
||
internal static class UnitParser | ||
{ | ||
[SuppressMessage("ReSharper", "UseStringInterpolation")] | ||
internal static TUnit ParseUnit<TUnit>([NotNull] string str, | ||
internal static TQuantity ParseUnit<TQuantityEnum, TQuantity>([NotNull] string str, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I renamed the type parameters to match a naming convention. |
||
[CanBeNull] IFormatProvider formatProvider, | ||
[NotNull] ParseUnit<TUnit> parseUnit, | ||
[NotNull] Func<TUnit, TUnit, TUnit> add) | ||
[NotNull] ParseUnit<TQuantity> parseUnit, | ||
[NotNull] Func<TQuantity, TQuantity, TQuantity> add) | ||
{ | ||
if (str == null) throw new ArgumentNullException(nameof(str)); | ||
if (parseUnit == null) throw new ArgumentNullException(nameof(parseUnit)); | ||
|
@@ -54,15 +54,23 @@ internal static TUnit ParseUnit<TUnit>([NotNull] string str, | |
|
||
const string exponentialRegex = @"(?:[eE][-+]?\d+)?)"; | ||
|
||
string[] unitAbbreviations = UnitSystem.GetCached(formatProvider) | ||
.GetAllAbbreviations(typeof(TQuantityEnum)) | ||
.OrderByDescending(s => s.Length) // Important to order by length -- if "m" is before "mm" and the input is "mm", it will match just "m" and throw invalid string error | ||
.Select(Regex.Escape) // Escape special regex characters | ||
.ToArray(); | ||
|
||
string unitsRegex = $"({String.Join("|", unitAbbreviations)})"; | ||
|
||
string regexString = string.Format(@"(?:\s*(?<value>[-+]?{0}{1}{2}{3})?{4}{5}", | ||
numRegex, // capture base (integral) Quantity value | ||
exponentialRegex, // capture exponential (if any), end of Quantity capturing | ||
@"\s?", // ignore whitespace (allows both "1kg", "1 kg") | ||
@"(?<unit>[^\s\d,]+)", // capture Unit (non-whitespace) input | ||
$@"(?<unit>{unitsRegex})", // capture Unit by list of abbreviations | ||
@"(and)?,?", // allow "and" & "," separators between quantities | ||
@"(?<invalid>[a-z]*)?"); // capture invalid input | ||
|
||
List<TUnit> quantities = ParseWithRegex(regexString, str, parseUnit, formatProvider); | ||
List<TQuantity> quantities = ParseWithRegex(regexString, str, parseUnit, formatProvider); | ||
if (quantities.Count == 0) | ||
{ | ||
throw new ArgumentException( | ||
|
@@ -74,14 +82,14 @@ internal static TUnit ParseUnit<TUnit>([NotNull] string str, | |
|
||
/// <summary> | ||
/// Parse a string given a particular regular expression. | ||
/// </summary> | ||
/// </summary> | ||
/// <exception cref="UnitsNetException">Error parsing string.</exception> | ||
private static List<TUnit> ParseWithRegex<TUnit>(string regexString, string str, ParseUnit<TUnit> parseUnit, | ||
private static List<TQuantity> ParseWithRegex<TQuantity>(string regexString, string str, ParseUnit<TQuantity> parseUnit, | ||
IFormatProvider formatProvider = null) | ||
{ | ||
var regex = new Regex(regexString); | ||
MatchCollection matches = regex.Matches(str.Trim()); | ||
var converted = new List<TUnit>(); | ||
var converted = new List<TQuantity>(); | ||
|
||
foreach (Match match in matches) | ||
{ | ||
|
@@ -121,4 +129,4 @@ private static List<TUnit> ParseWithRegex<TUnit>(string regexString, string str, | |
return converted; | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -445,6 +445,29 @@ public string[] GetAllAbbreviations(Type unitType, int unitValue) | |
: GetCached(FallbackCulture).GetAllAbbreviations(unitType, unitValue); | ||
} | ||
|
||
/// <summary> | ||
/// Get all abbreviations for unit. | ||
/// </summary> | ||
/// <param name="unitType">Enum type for unit.</param> | ||
/// <param name="unitValue">Enum value for unit.</param> | ||
/// <returns>Unit abbreviations associated with unit.</returns> | ||
[PublicAPI] | ||
public string[] GetAllAbbreviations(Type unitType) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Neat, this method has been requested before. |
||
{ | ||
Dictionary<int, List<string>> unitValueToAbbrevs; | ||
List<string> abbrevs = new List<string>(); | ||
|
||
if (_unitTypeToUnitValueToAbbrevs.TryGetValue(unitType, out unitValueToAbbrevs)) | ||
{ | ||
return unitValueToAbbrevs.Values.SelectMany(x => x).ToArray(); | ||
} | ||
|
||
// Fall back to default culture | ||
return IsFallbackCulture | ||
? new[] {$"(no abbreviations for {unitType.Name})"} | ||
: GetCached(FallbackCulture).GetAllAbbreviations(unitType); | ||
} | ||
|
||
private void LoadDefaultAbbreviations([NotNull] IFormatProvider culture) | ||
{ | ||
foreach (UnitLocalization localization in DefaultLocalizations) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized a better approach than using
UnitSystem.GetCached()
is to add a new ctor overload that allows you to disable default unit abbreviations from being loaded. I just added this in bf11a78.GetCached()
is not ideal, because it is.json
If
Length.json
already contained these units you are defining, you don't know for sure if the test passes due to callingMapUnitToAbbreviation
or not.So I would change this snippet to: