Devo analizzare la stringa "1.2345E-02" (un numero espresso in notazione esponenziale) in un tipo di dati decimale, ma Decimal.Parse("1.2345E-02")
genera semplicemente un errore
Risposte:
È un numero in virgola mobile, devi dirgli che:
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Funziona se specifichi NumberStyles.Float
:
decimal x = decimal.Parse("1.2345E-02", NumberStyles.Float);
Console.WriteLine(x); // Prints 0.012345
Non sono del tutto sicuro del motivo per cui questo non è supportato per impostazione predefinita: l'impostazione predefinita è utilizzare NumberStyles.Number
, che utilizza gli stili AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint e AllowThousands. Forse è correlato alle prestazioni; specificare un esponente è relativamente raro, suppongo.
decimal
con double
nel mio codice funziona bene per me, proprio come mi aspetterei. Se potessi fornire i dettagli di ciò che stai cercando di fare, il codice che stai utilizzando e il risultato, sarebbe molto più facile aiutare.
Oltre a specificare il NumberStyles, ti consiglio di utilizzare la funzione decimal.TryParse come:
decimal result;
if( !decimal.TryParse("1.2345E-02", NumberStyles.Any, CultureInfo.InvariantCulture, out result) )
{
// do something in case it fails?
}
In alternativa a NumberStyles, puoi usare un set specifico se sei certo dei tuoi formati. per esempio:
NumberStyles.AllowExponent | NumberStyles.Float
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Fai attenzione alla risposta selezionata: c'è una sottigliezza che specifica System.Globalization.NumberStyles.Float in Decimal.Parse che potrebbe portare a un'eccezione System.FormatException perché il tuo sistema potrebbe essere in attesa di un numero formattato con "," invece di "."
Ad esempio, in notazione francese, "1.2345E-02" non è valido, devi prima convertirlo in "1,2345E-02".
In conclusione, usa qualcosa sulla falsariga di:
Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);
Ho scoperto che il passaggio NumberStyles.Float
, in alcuni casi, modifica le regole con cui viene elaborata la stringa e produce un output diverso da NumberStyles.Number
(le regole predefinite utilizzate dadecimal.Parse
).
Ad esempio, il codice seguente genererà un FormatException
nella mia macchina:
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
Consiglierei di utilizzare l'input NumberStyles.Number | NumberStyles.AllowExponent
, poiché ciò consentirà numeri esponenziali e elaborerà comunque la stringa secondo le decimal
regole.
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
Per rispondere alla domanda del poster, la risposta giusta dovrebbe invece essere:
decimal x = decimal.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Console.WriteLine(x);
Avviso sull'utilizzo di NumberStyles.Any:
"6.33E + 03" viene convertito in 6330 come previsto. In tedesco, i punti decimali sono rappresentati da virgole, ma 6,33E + 03 viene convertito in 633000! Questo è un problema per i miei clienti, poiché la cultura che genera i dati non è nota e potrebbe essere diversa dalla cultura che opera sui dati. Nel mio caso, ho sempre la notazione scientifica, quindi posso sempre sostituire la virgola con il punto decimale prima dell'analisi, ma se stai lavorando con numeri arbitrari, come numeri abbastanza formattati come 1.234.567, questo approccio non funziona.
Non è necessario sostituire i punti (rispettivamente le virgole) basta specificare l'input 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"));
Se vuoi controllare e convertire il valore dell'esponente usa questo
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);
}
Spero che questo aiuti qualcuno.