Split string into decimal using any decimal separator

I want to parse a string from text input to decimal. The value represents the currency.

I currently got this solution:

private Decimal CastToDecimal(string value) 
{
    Decimal result;
    var valid = Decimal.TryParse(value, NumberStyles.Currency, null, out result);
    return valid ? result : -1;
}

      

It works very well so far, barring possible cultural differences. I am German and I expect most users to login in Francs style. But it is possible that someone is using "." instead of ",", and the conversion will fail.

"€ 123.45" => 123.45

"123.456.78 €" => 123456.78

"123.45 €" => 12345 <- I want the result to be 123.45 here

Is there a way to automatically detect the culture used for the decimal value? So it doesn't matter if you use German or English punctuation, will you still get the same result?

Update:

Thanks to your help, I have created a method that does what I want (I think).

private static Decimal CastToDecimal(string value)
{
    Decimal resultDe;
    Decimal resultEn;
    var style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands;
    var cultureDe = CultureInfo.CreateSpecificCulture("de-DE");
    var cultureEn = CultureInfo.CreateSpecificCulture("en-GB");
    var deValid = Decimal.TryParse(value, style, cultureDe, out resultDe);
    var enValid = Decimal.TryParse(value, style, cultureEn, out resultEn);
    var minVal = Math.Min(resultDe, resultEn);
    var maxVal = Math.Max(resultDe, resultEn);
    if (!deValid)
        return resultEn;
    if (!enValid)
        return resultDe;
    return BitConverter.GetBytes(decimal.GetBits(minVal)[3])[2] > 2 ? maxVal : minVal;
}

      

This code ...

    Console.WriteLine(CastToDecimal("123,45"));
    Console.WriteLine(CastToDecimal("123.45"));
    Console.WriteLine(CastToDecimal("123,450"));
    Console.WriteLine(CastToDecimal("123.450"));
    Console.WriteLine(CastToDecimal("123.123,45"));
    Console.WriteLine(CastToDecimal("123,123.45"));

      

returns this:

123,45
123,45
123450
123450
123123,45
123123,45

      

+3


source to share


4 answers


the solution at http://msdn.microsoft.com/en-us/library/3s27fasw%28v=vs.110%29.aspx which includes installing NumberStyle might be helpful.



...
value = "1.345,978";
style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands;
culture = CultureInfo.CreateSpecificCulture("es-ES");
if (Double.TryParse(value, style, culture, out number))
   Console.WriteLine("Converted '{0}' to {1}.", value, number);
else
   Console.WriteLine("Unable to convert '{0}'.", value);
// Displays:  
//       Converted '1.345,978' to 1345.978. 

value = "1 345,978";
if (Double.TryParse(value, style, culture, out number))
   Console.WriteLine("Converted '{0}' to {1}.", value, number);
else
   Console.WriteLine("Unable to convert '{0}'.", value);
...

      

+1


source


I ran into the same problem a while ago. My solution was to write my own parser in Java. The algorithm first clears the string. Below is a brief description:

  • Scan line from left to right
  • If char = '.' then dotFound = true; lastSeparatorPosition = index; dots ++
  • If char = ',' then commaFound = true; lastSeparatorPosition = index; commas ++
  • If dots == 0 && commas == 0 then its integer => done
  • If dots> 0 && commas> 0, then one of them by default SeparatorPosition is the decimal separator. Remove the rest from the line => done
  • / * only one type of separator * / if (periods + commas)> 1, then remove them // because there must be a thousand separator => done
  • / * the separator happens once * / if numberOfDigits to the right of the separator == 3, then you have to decide :-) either an integer or a decimal with 3 digits in a fraction


7 is the only remaining problem, as already mentioned, about maintaining security. Here you can only take into account the conceptual environment. All other cases are safe.

Good luck

+1


source


This cannot be done, simply because there are strings that make sense in two different cultures but mean different things. For example:

123.456

123,456

      

The first is slightly over 123 in the UK, but 123456 in Germany; the second is 123456 in the UK, but just over 123 in France.

0


source


The only solution is to add validation to the input and give the user and an example, by the way, if it's a web page, and then find a way to enter the data according to the user's culture. I suggest that you do not try to do what you are trying, because there is some culture that contradicts each other, for example in currency;

US / Australia / Many others use the following format

45,999.95

      

where, there are thousand separators and. is the decimal separator

whereas in some European countries

45.999,95  

      

means the same as above, but the thousands separator. and is used as a decimal separator.

Now the problem is that there is no guarantee that the user is using both the separator and your system can accept the thousands separator as decimal, etc.

If you really don't want to disturb the user, then create separate input fields for the major and minor currencies.

So it's best not to go there. I believe this might help. Happy coding :)

Update

Same case with date format, for example. in US format, month comes first, followed by day, while Australia day comes first, and then month; now 02/01/2015

typing would mean that the system cannot tell the user's intent differently.

0


source







All Articles