diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt index a94665fa7..02f8be867 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -412,8 +412,8 @@ namespace Humanizer public class static MetricNumeralExtensions { public static double FromMetric(this string input) { } - public static string ToMetric(this int input, bool hasSpace = False, bool useSymbol = True, System.Nullable decimals = null) { } - public static string ToMetric(this double input, bool hasSpace = False, bool useSymbol = True, System.Nullable decimals = null) { } + public static string ToMetric(this int input, bool hasSpace = False, bool useSymbol = True, System.Nullable decimals = null, System.Nullable largestPrefix = null) { } + public static string ToMetric(this double input, bool hasSpace = False, bool useSymbol = True, System.Nullable decimals = null, System.Nullable largestPrefix = null) { } } public class NoMatchFoundException : System.Exception { diff --git a/src/Humanizer/MetricNumeralExtensions.cs b/src/Humanizer/MetricNumeralExtensions.cs index 5ce9a3e2d..bb1fa37a1 100644 --- a/src/Humanizer/MetricNumeralExtensions.cs +++ b/src/Humanizer/MetricNumeralExtensions.cs @@ -101,17 +101,19 @@ public static double FromMetric(this string input) /// True will split the number and the symbol with a whitespace. /// True will use symbol instead of name /// If not null it is the numbers of decimals to round the number to + /// If not null it is the largest prefix used in result. /// /// /// 1000.ToMetric() => "1k" /// 123.ToMetric() => "123" /// 1E-1.ToMetric() => "100m" + /// 1_000_000.ToMetric(largestPrefix = 'k') => "1000k" /// /// /// A valid Metric representation - public static string ToMetric(this int input, bool hasSpace = false, bool useSymbol = true, int? decimals = null) + public static string ToMetric(this int input, bool hasSpace = false, bool useSymbol = true, int? decimals = null, char? largestPrefix = null) { - return ((double)input).ToMetric(hasSpace, useSymbol, decimals); + return ((double)input).ToMetric(hasSpace, useSymbol, decimals, largestPrefix); } /// @@ -125,15 +127,17 @@ public static string ToMetric(this int input, bool hasSpace = false, bool useSym /// True will split the number and the symbol with a whitespace. /// True will use symbol instead of name /// If not null it is the numbers of decimals to round the number to + /// If not null it is the largest prefix used in result. /// /// /// 1000d.ToMetric() => "1k" /// 123d.ToMetric() => "123" /// 1E-1.ToMetric() => "100m" + /// 1_000_000.ToMetric(largestPrefix = 'k') => "1000k" /// /// /// A valid Metric representation - public static string ToMetric(this double input, bool hasSpace = false, bool useSymbol = true, int? decimals = null) + public static string ToMetric(this double input, bool hasSpace = false, bool useSymbol = true, int? decimals = null, char? largestPrefix = null) { if (input.Equals(0)) { @@ -145,7 +149,7 @@ public static string ToMetric(this double input, bool hasSpace = false, bool use throw new ArgumentOutOfRangeException(nameof(input)); } - return BuildRepresentation(input, hasSpace, useSymbol, decimals); + return BuildRepresentation(input, hasSpace, useSymbol, decimals, largestPrefix); } /// @@ -217,13 +221,14 @@ private static string ReplaceNameBySymbol(string input) /// True will split the number and the symbol with a whitespace. /// True will use symbol instead of name /// If not null it is the numbers of decimals to round the number to + /// If not null it is the largest prefix used in result. /// A number in a Metric representation - private static string BuildRepresentation(double input, bool hasSpace, bool useSymbol, int? decimals) + private static string BuildRepresentation(double input, bool hasSpace, bool useSymbol, int? decimals, char? largestPrefix = null) { var exponent = (int)Math.Floor(Math.Log10(Math.Abs(input)) / 3); return exponent.Equals(0) ? input.ToString() - : BuildMetricRepresentation(input, exponent, hasSpace, useSymbol, decimals); + : BuildMetricRepresentation(input, exponent, hasSpace, useSymbol, decimals, largestPrefix); } /// @@ -234,9 +239,13 @@ private static string BuildRepresentation(double input, bool hasSpace, bool useS /// True will split the number and the symbol with a whitespace. /// True will use symbol instead of name /// If not null it is the numbers of decimals to round the number to + /// If not null it is the largest prefix used in result. /// A number in a Metric representation - private static string BuildMetricRepresentation(double input, int exponent, bool hasSpace, bool useSymbol, int? decimals) + private static string BuildMetricRepresentation(double input, int exponent, bool hasSpace, bool useSymbol, int? decimals, char? largestPrefix = null) { + if (largestPrefix != null) + exponent = LimitExponent(exponent, (char)largestPrefix); + var number = input * Math.Pow(1000, -exponent); if (decimals.HasValue) { @@ -251,6 +260,18 @@ private static string BuildMetricRepresentation(double input, int exponent, bool + GetUnit(symbol, useSymbol); } + // TODO docs + private static int LimitExponent(int exponent, char largestPrefix) + { + // TODO largestPrefix = largestPrefix.Trim(); When changed to string + + if (!(Symbols[0].Contains(largestPrefix) || Symbols[1].Contains(largestPrefix))) + throw new ArgumentException("Empty or invalid Metric prefix character.", nameof(largestPrefix)); // TODO change to "string". + + return exponent; // TODO + } + + /// /// Get the unit from a symbol of from the symbol's name. /// @@ -265,7 +286,7 @@ private static string GetUnit(char symbol, bool useSymbol) /// /// Check if a Metric representation is out of the valid range. /// - /// A Metric representation who might be out of the valid range. + /// A Metric representation that may be out of the valid range. /// True if input is out of the valid range. private static bool IsOutOfRange(this double input) { @@ -283,7 +304,7 @@ private static bool IsOutOfRange(this double input) /// /// ToDo: Performance: Use (string input, out number) to escape the double use of Parse() /// - /// A string who might contain a invalid Metric representation. + /// A string that may contain an invalid Metric representation. /// True if input is not a valid Metric representation. private static bool IsInvalidMetricNumeral(this string input) { @@ -292,5 +313,10 @@ private static bool IsInvalidMetricNumeral(this string input) var isSymbol = Symbols[0].Contains(last) || Symbols[1].Contains(last); return !double.TryParse(isSymbol ? input.Remove(index) : input, out var number); } + + private static bool IsInvalidMetricPrefix(this string input) + { + return false; //TODO + } } }