Andrzej Gis
Andrzej Gis

Reputation: 14306

How to make decimal.Parse accept multiple cultures

I need to accept 3 decimal data formats in my app:

I cannot assume that one format will be used in particular situation. What I need is get a decimal value from a string no matter in which format it's given.

Is there a smart way to do this?

I was trying to use

var culture = CultureInfo.CreateSpecificCulture("en-US");

but this doesn't seem to work on wp7.

So far I've done this:

public static class Extensions
{

    public static decimal toDecimal(this string s)
    {
        decimal res;

        int comasCount=0;
        int periodsCount=0;

        foreach (var c in s)
        {
            if (c == ',')
                comasCount++;
            else if (c == '.')
                periodsCount++;
        }

        if (periodsCount > 1)
            throw new FormatException();
        else if(periodsCount==0 && comasCount > 1)
            throw new FormatException();

        if(comasCount==1)
        {
            // pl-PL
            //parse here
        }else
        {
            //en-US
            //parse here
        }

        return res;
    }
}

Upvotes: 6

Views: 2990

Answers (3)

Nicholas Carey
Nicholas Carey

Reputation: 74267

You might try something like this:

public static decimal ParseDecimalNumber( string s , string groupSeparators , string decimalPoints )
{
  NumberFormatInfo nfi   = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone() ;
  NumberStyles     style = NumberStyles.AllowLeadingWhite
                         | NumberStyles.AllowLeadingSign
                         | NumberStyles.AllowThousands
                         | NumberStyles.AllowDecimalPoint
                         | NumberStyles.AllowTrailingSign
                         | NumberStyles.AllowTrailingWhite
                         ;
  decimal          value ;
  bool             parsed = false ;

  for ( int i = 0 ; !parsed && i < groupSeparators.Length ; ++i )
  {

    nfi.NumberGroupSeparator = groupSeparators.Substring(i,1) ;

    for ( int j = 0 ; !parsed && j < decimalPoints.Length ; ++j )
    {
      if ( groupSeparators[i] == decimalPoints[j] ) continue ; // skip when group and decimal separator are identical

      nfi.NumberDecimalSeparator = decimalPoints.Substring(j,1) ;

      parsed = Decimal.TryParse( s , style , nfi , out value ) ;

    }
  }

  if ( !parsed ) throw new ArgumentOutOfRangeException("s") ;

  return value ;

}

Usage is simple:

string groupSeparators = "., " ;
string decimalPoints   = ".,"  ;
Decimal value = ParseDecimalNumber( someStringContainingANumericLiteral , groupSeparators , decimalPoints ) ;

Upvotes: 2

Peter Ritchie
Peter Ritchie

Reputation: 35881

Try using var culture = new CultureInfo("en-US"); to create the culture. Passing that culture to decimal.Parse or decimal.TryParse will parse the text appropriately for each culture.

Now, keep in mind that each culture may parse the text without failure but not parse it the way it's represented for the original culture. For example decimal.TryParse("1000,314", NumberStyles.Number, new CultureInfo("en-US"), out result) will result success and 1000314m, not 1000.314m. Whereas decimal.TryParse("1000,314", NumberStyles.Number, new CultureInfo("fr-FR"), out result) will result in 1000.314m.

Upvotes: 4

Christoffer Lette
Christoffer Lette

Reputation: 14816

Three calls to TryParse with different NumberStyles and IFormatProvider set to null should do it.

Upvotes: 0

Related Questions