[ACCEPTED]-C# Decimal.Parse issue with commas-decimal
It's allowing thousands, because the default 5 NumberStyles
value used by Decimal.Parse
(NumberStyles.Number
) includes NumberStyles.AllowThousands
.
If you want 4 to disallow the thousands separators, you 3 can just remove that flag, like this:
Decimal.Parse("1,2,3,4", NumberStyles.Number ^ NumberStyles.AllowThousands)
(the 2 above code will throw an InvalidFormatException
, which is what 1 you want, right?)
I ended up having to write the code to verify 9 the currency manually. Personally, for a 8 framework that prides itself for having 7 all the globalization stuff built in, it's 6 amazing .NET doesn't have anything to handle 5 this.
My solution is below. It works for 4 all the locales in the framework. It doesn't 3 support Negative numbers, as Orion pointed 2 out below, though. What do you guys think?
public static bool TryParseCurrency(string value, out decimal result)
{
result = 0;
const int maxCount = 100;
if (String.IsNullOrEmpty(value))
return false;
const string decimalNumberPattern = @"^\-?[0-9]{{1,{4}}}(\{0}[0-9]{{{2}}})*(\{0}[0-9]{{{3}}})*(\{1}[0-9]+)*$";
NumberFormatInfo format = CultureInfo.CurrentCulture.NumberFormat;
int secondaryGroupSize = format.CurrencyGroupSizes.Length > 1
? format.CurrencyGroupSizes[1]
: format.CurrencyGroupSizes[0];
var r = new Regex(String.Format(decimalNumberPattern
, format.CurrencyGroupSeparator==" " ? "s" : format.CurrencyGroupSeparator
, format.CurrencyDecimalSeparator
, secondaryGroupSize
, format.CurrencyGroupSizes[0]
, maxCount), RegexOptions.Compiled | RegexOptions.CultureInvariant);
return !r.IsMatch(value.Trim()) ? false : Decimal.TryParse(value, NumberStyles.Any, CultureInfo.CurrentCulture, out result);
}
And 1 here's one test to show it working (nUnit):
[Test]
public void TestCurrencyStrictParsingInAllLocales()
{
var originalCulture = CultureInfo.CurrentCulture;
var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
const decimal originalNumber = 12345678.98m;
foreach(var culture in cultures)
{
var stringValue = originalNumber.ToCurrencyWithoutSymbolFormat();
decimal resultNumber = 0;
Assert.IsTrue(DecimalUtils.TryParseCurrency(stringValue, out resultNumber));
Assert.AreEqual(originalNumber, resultNumber);
}
System.Threading.Thread.CurrentThread.CurrentCulture = originalCulture;
}
You might be able to do this in a two-phase 4 process. First you could verify the thousands 3 separator using the information in the CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator
and 2 CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes
throwing an exception if it doesn't pass 1 and then pass the number into the Decimal.Parse()
;
It is a common issue never solved by microsoft. So, I 13 don't understand why 1,2,3.00 (english culture 12 for example) is valid! You need to build 11 an algorith to examine group size and return 10 false/exception(like a failed double.parse) if 9 the test is not passed. I had a similar 8 problem in a mvc application, which build 7 in validator doesn't accept thousands..so 6 i've overwrite it with a custom, using double/decimal/float.parse, but 5 adding a logic to validate group size.
If 4 you want read my solution (it is used for 3 my mvc custom validator, but you can use 2 it to have a better double/decimal/float.parse 1 generic validator) go here https://stackoverflow.com/a/41916721/3930528
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.