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
C'est un nombre à virgule flottante, vous devez lui dire que:
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
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.
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
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
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);
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);
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.
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.
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"));