285 votes

Comment analyser une chaîne de caractères avec un point décimal en un double ?

Je veux analyser une chaîne de caractères comme "3.5" à un double. Cependant,

double.Parse("3.5") 

donne 35 et

double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint) 

lance un FormatException .

Or, la locale de mon ordinateur est réglée sur l'allemand, où une virgule est utilisée comme séparateur décimal. Il se peut qu'il y ait un rapport avec cela et double.Parse() en attendant "3,5" comme entrée, mais je ne suis pas sûr.

Comment puis-je analyser une chaîne contenant un nombre décimal qui peut ou non être formaté comme spécifié dans ma locale actuelle ?

1voto

JanW Points 1150

Cela fait le travail dans n'importe quel scénario. C'est un peu plus compliqué.

List<string> inputs = new List<string>()
{
    "1.234.567,89",
    "1 234 567,89",
    "1 234 567.89",
    "1,234,567.89",
    "123456789",
    "1234567,89",
    "1234567.89",
};
string output;

foreach (string input in inputs)
{
    // unify string (no spaces, only . )
    output = input.Trim().Replace(" ", "").Replace(",", ".");

    // split it on points
    string[] split = output.Split('.');

    if (split.Count() > 1)
    {
        // take all parts except last
        output = string.Join("", split.Take(split.Count()-1).ToArray());

        // combine token parts with last part
        output = string.Format("{0}.{1}", output, split.Last());
    }

    // parse double invariant
    double d = double.Parse(output, CultureInfo.InvariantCulture);
    Console.WriteLine(d);
}

1voto

Schorsch Points 42

Je pense qu'une conversion 100% correcte n'est pas possible, si la valeur provient d'une entrée utilisateur. Par exemple, si la valeur est 123.456, il peut s'agir d'un groupement ou d'un point décimal. Si vous avez vraiment besoin de 100%, vous devez décrire votre format et lever une exception s'il n'est pas correct.

Mais j'ai amélioré le code de JanW, ce qui nous permet d'avancer un peu plus vers les 100%. L'idée est que si le dernier séparateur est un groupSeperator, il s'agit plutôt d'un type entier que double.

Le code ajouté est dans le premier si de GetDouble .

void Main()
{
    List<string> inputs = new List<string>() {     
        "1.234.567,89",     
        "1 234 567,89",     
        "1 234 567.89",     
        "1,234,567.89",    
        "1234567,89",     
        "1234567.89",  
        "123456789",   
        "123.456.789", 
        "123,456,789,"
    }; 

    foreach(string input in inputs) {
        Console.WriteLine(GetDouble(input,0d));
    }

}

public static double GetDouble(string value, double defaultValue) {
    double result;
    string output;

    // check if last seperator==groupSeperator
    string groupSep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator;
    if (value.LastIndexOf(groupSep) + 4 == value.Count())
    {
        bool tryParse = double.TryParse(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.CurrentCulture, out result);
        result = tryParse ? result : defaultValue;
    } 
    else 
    {
        // unify string (no spaces, only . )     
        output = value.Trim().Replace(" ", string.Empty).Replace(",", ".");      

        // split it on points     
        string[] split = output.Split('.');      

        if (split.Count() > 1)     
        {         
            // take all parts except last         
            output = string.Join(string.Empty, split.Take(split.Count()-1).ToArray()); 

            // combine token parts with last part         
            output = string.Format("{0}.{1}", output, split.Last());     
        }      
        // parse double invariant     
        result = double.Parse(output, System.Globalization.CultureInfo.InvariantCulture);             
    }
    return result;
}

0voto

JacekK Points 1

J'ai aussi amélioré le code de @JanW...

J'en ai besoin pour formater les résultats des instruments médicaux, ils envoient aussi ">1000", "23.3e02", "350E-02", "NEGATIF".

private string FormatResult(string vResult)
{
  string output;
  string input = vResult;

  // unify string (no spaces, only . ) 
  output = input.Trim().Replace(" ", "").Replace(",", ".");

  // split it on points 
  string[] split = output.Split('.');

  if (split.Count() > 1)
  {
    // take all parts except last 
    output = string.Join("", split.Take(split.Count() - 1).ToArray());

    // combine token parts with last part 
    output = string.Format("{0}.{1}", output, split.Last());
  }
  string sfirst = output.Substring(0, 1);

  try
  {
    if (sfirst == "<" || sfirst == ">")
    {
      output = output.Replace(sfirst, "");
      double res = Double.Parse(output);
      return String.Format("{1}{0:0.####}", res, sfirst);
    }
    else
    {
      double res = Double.Parse(output);
      return String.Format("{0:0.####}", res);
    }
  }
  catch
  {
    return output;
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X