Analizza un numero dalla notazione esponenziale


85

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:


169

È un numero in virgola mobile, devi dirgli che:

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

49

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.


Sto cercando di farlo funzionare con il doppio ma sembra che non lo farà. Non sei sicuro del motivo per cui non potrebbe ..?
1919

@ JanT: Senza più informazioni di "non lo farà" e "non potrebbe" non posso davvero aiutare di più. Ti suggerisco di fare una nuova domanda con molti più dettagli, mostrando cosa hai provato ed esattamente cosa è successo.
Jon Skeet il

Ho provato a eseguire il codice come nella tua risposta, ma invece del doppio decimale usato. Ma già trovato soluzione alternativa. Saluti
1919

1
@ JanT Sarebbe bello se potessi condividere la tua soluzione alternativa. Ho esattamente lo stesso problema e potrei usare le informazioni. Grazie!
Rick Glimmer

@ RickGlimmer: Non sono sicuro di come tu sappia che il tuo problema è esattamente lo stesso di JanT, dato che non hanno mai fornito dettagli su ciò che stavano cercando di fare. La sostituzione decimalcon doublenel 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.
Jon Skeet

34

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

1
Ma non è necessario utilizzare Float con AllowExponent perché Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent
Lukáš Kmoch

@ LukášKmoch In effetti hai ragione. Forza dell'abitudine come gli altri (a parte Qualsiasi) non la includono. Tuttavia, non dovrebbe far male eseguire l'OR extra.
Sverrir Sigmundarson

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

8

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);

1
Hai assolutamente ragione. Non capisco perché nessun altro ne abbia parlato.
Carles Alcolea

10
Meglio usare CultureInfo.InvariantCulture come terzo parametro di Parse
Andriy Kozachuk

3

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 FormatExceptionnella 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 decimalregole.

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);

1

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.


0

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"));

0

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.