Analysieren Sie eine Zahl aus der Exponentialnotation

85

Ich muss die Zeichenfolge "1.2345E-02" (eine Zahl in Exponentialschreibweise) auf einen dezimalen Datentyp analysieren, löst aber Decimal.Parse("1.2345E-02")einfach einen Fehler aus

Jimbo
quelle

Antworten:

168

Es ist eine Gleitkommazahl, Sie müssen sagen, dass:

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

Es funktioniert, wenn Sie Folgendes angeben NumberStyles.Float:

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

Ich bin mir nicht ganz sicher, warum dies nicht standardmäßig unterstützt wird. Standardmäßig NumberStyles.Numberwerden die Stile AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint und AllowThousands verwendet. Möglicherweise ist es leistungsbezogen; Die Angabe eines Exponenten ist vermutlich relativ selten.

Jon Skeet
quelle
Ich versuche, dies mit Double zum Laufen zu bringen, aber es scheint, dass dies nicht der Fall ist. Nicht sicher, warum es nicht konnte ..?
jant
@JanT: Mit nicht mehr Informationen als "es wird nicht" und "es konnte nicht" kann ich nicht wirklich mehr helfen. Ich schlage vor, Sie stellen eine neue Frage mit viel mehr Details, die zeigt, was Sie versucht haben und was genau passiert ist.
Jon Skeet
Ich habe versucht, Code wie in Ihrer Antwort auszuführen, aber anstelle der Dezimalzahl wird double verwendet. Aber schon Workaround gefunden. Prost
JanT
1
@ JanT Es wäre schön, wenn Sie Ihre Problemumgehung teilen könnten. Ich habe genau das gleiche Problem und könnte die Informationen verwenden. Vielen Dank!
Rick Glimmer
@ RickGlimmer: Ich bin mir nicht sicher, woher Sie wissen, dass Ihr Problem genau das gleiche ist wie das von JanT, da sie nie detailliert angegeben haben, was sie versucht haben. Das Ersetzen decimaldurch doublein meinem Code funktioniert für mich gut, genau wie ich es erwarten würde. Wenn Sie Details zu dem, was Sie versuchen, dem von Ihnen verwendeten Code und dem Ergebnis angeben könnten , wäre es viel einfacher zu helfen.
Jon Skeet
34

Zusätzlich zur Angabe der NumberStyles würde ich empfehlen, dass Sie die Funktion decimal.TryParse verwenden, z.

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

Als Alternative zu NumberStyles. Sie können einen bestimmten Satz verwenden, wenn Sie sich Ihrer Formate sicher sind. z.B:

NumberStyles.AllowExponent | NumberStyles.Float
Sverrir Sigmundarson
quelle
1
Es ist jedoch nicht erforderlich, Float mit AllowExponent zu verwenden, da Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent
Lukáš Kmoch
@ LukášKmoch In der Tat hast du recht. Die Kraft der Gewohnheit, wie sie die anderen (außer Any) nicht einschließen. Sollte aber nicht schaden, den zusätzlichen OP durchzuführen.
Sverrir Sigmundarson
13
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Mitch Wheat
quelle
8

Seien Sie vorsichtig mit der ausgewählten Antwort: Es gibt eine Subtilität, die System.Globalization.NumberStyles.Float in Decimal.Parse angibt. Dies kann zu einer System.FormatException führen, da Ihr System möglicherweise auf eine mit ',' anstelle von ' formatierte Zahl wartet.

In der französischen Notation ist beispielsweise "1.2345E-02" ungültig. Sie müssen es zuerst in "1.2345E-02" konvertieren.

Verwenden Sie abschließend etwas in der Art von:

Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);
KwentRell
quelle
1
Du hast absolut recht. Ich verstehe nicht, warum es sonst niemand angesprochen hat.
Carles Alcolea
10
Verwenden Sie besser CultureInfo.InvariantCulture als 3. Parameter von Parse
Andriy Kozachuk
3

Ich habe festgestellt, dass das Übergeben in NumberStyles.Floateinigen Fällen die Regeln ändert, nach denen die Zeichenfolge verarbeitet wird, und zu einer anderen Ausgabe führt als NumberStyles.Number(die von verwendeten Standardregeln decimal.Parse).

Der folgende Code generiert beispielsweise ein FormatExceptionin meinem Computer:

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

Ich würde empfehlen, die Eingabe zu verwenden NumberStyles.Number | NumberStyles.AllowExponent , da dies Exponentialzahlen zulässt und die Zeichenfolge weiterhin gemäß den decimalRegeln verarbeitet.

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

Um die Frage des Posters zu beantworten, sollte die richtige Antwort stattdessen lauten:

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

Warnung zur Verwendung von NumberStyles.Any:

"6.33E + 03" wird wie erwartet in 6330 konvertiert. Im Deutschen werden Dezimalstellen durch Kommas dargestellt, aber 6,33E + 03 werden in 633000 konvertiert! Dies ist ein Problem für meine Kunden, da die Kultur, die die Daten generiert, nicht bekannt ist und sich möglicherweise von der Kultur unterscheidet, die mit den Daten arbeitet. In meinem Fall habe ich immer eine wissenschaftliche Notation, daher kann ich vor dem Parsen immer das Komma durch einen Dezimalpunkt ersetzen. Wenn Sie jedoch mit beliebigen Zahlen wie hübsch formatierten Zahlen wie 1.234.567 arbeiten, funktioniert dieser Ansatz nicht.

David Kitzinger
quelle
0

Sie müssen die Punkte (bzw. Kommas) nicht ersetzen, sondern geben nur die Eingabe IFormatProvider an:

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"));
sterblich
quelle
0

Wenn Sie den Exponentenwert überprüfen und konvertieren möchten, verwenden Sie diesen

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

Hoffe das hilft jemandem.

RAM
quelle