web-dev-qa-db-fra.com

Analyser un nombre à partir d'une notation exponentielle

J'ai besoin d'analyser la chaîne "1.2345E-02" (un nombre exprimé en notation exponentielle) en un type de données décimal, mais Decimal.Parse("1.2345E-02") jette simplement une erreur

76
Jimbo

C'est un nombre à virgule flottante, vous devez lui dire que:

decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
156
Hans Passant

Cela fonctionne si vous spécifiez NumberStyles.Float :

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Float);
Console.WriteLine(x); // Prints 0.012345

Je ne sais pas vraiment pourquoi cela n'est pas pris en charge par défaut - la valeur par défaut est d'utiliser NumberStyles.Number, qui utilise les styles AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint et AllowThousands. C'est peut-être lié aux performances; spécifier un exposant est relativement rare, je suppose.

44
Jon Skeet

En plus de spécifier les NumberStyles, je vous recommande d'utiliser la fonction decimal.TryParse telle que:

decimal result;
if( !decimal.TryParse("1.2345E-02", NumberStyles.Any, CultureInfo.InvariantCulture, out result) )
{
     // do something in case it fails?
}

Comme alternative à NumberStyles, vous pouvez utiliser un ensemble spécifique si vous êtes certain de vos formats. par exemple:

NumberStyles.AllowExponent | NumberStyles.Float
32
Sverrir Sigmundarson
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
11
Mitch Wheat

Soyez prudent sur la réponse sélectionnée: il existe une subtilité spécifiant System.Globalization.NumberStyles.Float in Decimal.Parse qui pourrait conduire à une System.FormatException car votre système attend peut-être un nombre formaté avec ',' au lieu de '.'

Par exemple, en notation française, "1.2345E-02" n'est pas valide, vous devez d'abord le convertir en "1,2345E-02".

En conclusion, utilisez quelque chose comme:

Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);
7
KwentRell

J'ai trouvé qu'en passant NumberStyles.Float, dans certains cas, modifie les règles selon lesquelles la chaîne est traitée et entraîne une sortie différente de NumberStyles.Number (les règles par défaut utilisées par decimal.Parse).

Par exemple, le code suivant générera un FormatException sur ma machine:

CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5", NumberStyles.Float, culture); // FormatException thrown here

Je recommande d'utiliser l'entrée NumberStyles.Number | NumberStyles.AllowExponent, car cela autorisera les nombres exponentiels et traitera toujours la chaîne selon les règles decimal.

CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5",NumberStyles.Number | NumberStyles.AllowExponent, culture); // Does not generate a FormatException

Pour répondre à la question de l'affiche, la bonne réponse devrait plutôt être:

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Console.WriteLine(x);
3
bastos.sergio

Avertissement sur l'utilisation de NumberStyles.Any:

"6.33E + 03" est converti en 6330 comme prévu. En allemand, les points décimaux sont représentés par des virgules, mais 6,33E + 03 convertit en 633000! C'est un problème pour mes clients, car la culture qui génère les données n'est pas connue et peut être différente de la culture qui opère sur les données. Dans mon cas, j'ai toujours une notation scientifique, donc je peux toujours remplacer la virgule par une virgule décimale avant l'analyse, mais si vous travaillez avec des nombres arbitraires, comme des nombres assez formatés comme 1234567, cette approche ne fonctionne pas.

1
David Kitzinger

Si vous voulez vérifier et convertir la valeur de l'exposant, utilisez ceci

string val = "1.2345E-02";
double dummy;
bool hasExponential = (val.Contains("E") || val.Contains("e")) && double.TryParse(val, out dummy);
if (hasExponential)
{
    decimal d = decimal.Parse(val, NumberStyles.Float);
}

J'espère que cela aide quelqu'un.

0
rAm

Vous n'avez pas besoin de remplacer les points (respectivement les virgules), spécifiez simplement l'entrée IFormatProvider:

float d = Single.Parse("1.27315", System.Globalization.NumberStyles.Float, new CultureInfo("en-US"));
float d = Single.Parse("1,27315", System.Globalization.NumberStyles.Float, new CultureInfo("de-DE"));
0
mortal