stackdisplay
stackdisplay

Reputation: 2045

C# thousand separator issue with decimal.tryparse

I am not sure how this is able to be parsed correctly in C# but I would like it to fail where the case where the comma is not separated every repeatable three value. Example: 1,123.23 should pass but 11,23.23 should fail in my sense. But the actual output is that tryparse seems to always return true regardless of where the position of comma is before decimal.

Edit: Answer with regex is being accepted since it is found that this is a bug. Thank you.

 string price = "1,1,2,3.23";
 decimal outputValue = 0;
 var allowedStyles = (NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands);


 if (Decimal.TryParse(price, allowedStyles, CultureInfo.GetCultureInfo("EN-us"), out outputValue))
 {
    Console.WriteLine("Pass");
 }

Upvotes: 9

Views: 2926

Answers (5)

g.pickardou
g.pickardou

Reputation: 35873

What you discovered is clearly a bug. I strongly recommend do not stuck here, instead implement a workaround. (and also apply KISS).

Unless this code part executed zillion ad zillion times in a high math algorithm's core or any other way is performance critical, here is a simple workaround.

(Supposing the strings are using ',' (comma) as thousand separator. (and they are not decimal separator as it could be some culture)):

price = price.Replace(",",""); // This will not change the value when comma is thousand separator.
// Go forward to parsing

Upvotes: 2

Andrew Morton
Andrew Morton

Reputation: 25023

You have two acceptable formats, so you can check if the number is parseable and, if so, check it is in an acceptable format:

string price = "1,123.23";
decimal outputValue = 0;
var allowedStyles = (NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands);
var cul = CultureInfo.GetCultureInfo("EN-us");

if (decimal.TryParse(price, allowedStyles, cul, out outputValue))
{
    if (outputValue.ToString("N", cul) == price || outputValue.ToString("G", cul) == price)
    {
        Console.WriteLine("Pass");
    }
}

Upvotes: 2

huysentruitw
huysentruitw

Reputation: 28111

As you noted NumberStyles.AllowThousands doesn't enforce the comma to be on the correct place. So I think a regular expression can help you here:

Regex.IsMatch("11,23.23", "^[+-]?[0-9]{1,3}(,[0-9]{3})*(.[0-9]*)?$");

Upvotes: 4

ken lacoste
ken lacoste

Reputation: 894

I don't know if this helps but, yeah I think I should try. I think my answer is a little but straight forward, just if the concern is the format, I made it compare on a .ToString("format specified"); and compare it to your "price" string. Just my 2 cents.

string price = "1,1,2,3.23";
decimal priceParse = 0;

if (decimal.TryParse(price, out priceParse))
{
     string shouldBeFormat = Convert.ToDecimal(priceParse).ToString("#,##0.00");

     if (price == shouldBeFormat)
     {
        // your good
     }
     else
     {
        // no good
     }
}

Upvotes: 3

Moradnejad
Moradnejad

Reputation: 3653

I ran a few different codes and i realized when you apply AllowThousands, the only constraint on the place of ',' is that it should be on the integer part of the number.

some results:

  • "123,,3.12" => pass
  • "123,,3.1,3" => fail

Upvotes: 1

Related Questions