Analizar un número a partir de notación exponencial

85

Necesito analizar la cadena "1.2345E-02" (un número expresado en notación exponencial) a un tipo de datos decimal, pero Decimal.Parse("1.2345E-02")simplemente arroja un error

Jimbo
fuente

Respuestas:

169

Es un número de coma flotante, tienes que decirle que:

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

Funciona si especifica NumberStyles.Float:

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

No estoy del todo seguro de por qué esto no es compatible de forma predeterminada: el valor predeterminado es usar NumberStyles.Number, que usa los estilos AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint y AllowThousands. Posiblemente esté relacionado con el rendimiento; especificar un exponente es relativamente raro, supongo.

Jon Skeet
fuente
Estoy tratando de que esto funcione con el doble, pero parece que no lo hará. ¿No estás seguro de por qué no pudo ...?
EneT
@JanT: Sin más información que "no lo hará" y "no podría", no puedo ayudar más. Le sugiero que haga una nueva pregunta con mucho más detalle, mostrando lo que intentó y exactamente lo que sucedió.
Jon Skeet
Intenté ejecutar un código como en su respuesta, pero en lugar de decimal usé double. Pero ya encontré una solución. Saludos
JanT
1
@JanT Sería bueno si pudiera compartir su solución. Tengo exactamente el mismo problema y podría usar la información. ¡Gracias!
Rick Glimmer
@RickGlimmer: No estoy seguro de cómo sabe que su problema es exactamente el mismo que el de JanT, dado que nunca proporcionaron detalles de lo que estaban tratando de hacer. Sustitución decimalcon doubleen mi código bien funciona para mí, así como yo esperaría que lo haga. Si pudiera proporcionar detalles de lo que está intentando, el código que está utilizando y el resultado, sería mucho más fácil ayudar.
Jon Skeet
34

Además de especificar los NumberStyles, le recomendaría que utilice la función decimal.TryParse como:

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

Como alternativa a NumberStyles, cualquiera puede usar un conjunto específico si está seguro de sus formatos. p.ej:

NumberStyles.AllowExponent | NumberStyles.Float
Sverrir Sigmundarson
fuente
1
Pero no es necesario usar Float con AllowExponent porque Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent
Lukáš Kmoch
@ LukášKmoch De hecho, tienes razón. Fuerza del hábito ya que los demás (aparte de Cualquiera) no lo incluyen. Sin embargo, no debería doler realizar el quirófano adicional.
Sverrir Sigmundarson
13
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Trigo Mitch
fuente
8

Tenga cuidado con la respuesta seleccionada: hay una sutileza que especifica System.Globalization.NumberStyles.Float en Decimal.Parse que podría llevar a una System.FormatException porque su sistema podría estar esperando un número formateado con ',' en lugar de '.'

Por ejemplo, en la notación francesa, "1.2345E-02" no es válido, primero debe convertirlo a "1,2345E-02".

En conclusión, use algo como:

Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);
KwentRell
fuente
1
Estás absolutamente en lo correcto. No entiendo por qué nadie más lo mencionó.
Carles Alcolea
10
Mejor uso CultureInfo.InvariantCulture como tercer parámetro de Parse
Andriy Kozachuk
3

Descubrí que pasar NumberStyles.Float, en algunos casos, cambia las reglas por las cuales se procesa la cadena y da como resultado una salida diferente de NumberStyles.Number(las reglas predeterminadas utilizadas pordecimal.Parse ).

Por ejemplo, el siguiente código generará un FormatExceptionen mi máquina:

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

Recomendaría usar la entrada NumberStyles.Number | NumberStyles.AllowExponent, ya que esto permitirá números exponenciales y aún procesará la cadena según las decimalreglas.

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

Para responder a la pregunta del cartel, la respuesta correcta debería ser:

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

Advertencia sobre el uso de NumberStyles.

"6.33E + 03" se convierte en 6330 como se esperaba. En alemán, los puntos decimales se representan con comas, ¡pero 6,33E + 03 se convierte en 633000! Esto es un problema para mis clientes, ya que la cultura que genera los datos no es conocida y puede ser diferente a la cultura que opera sobre los datos. En mi caso, siempre tengo notación científica, por lo que siempre puedo reemplazar la coma por el punto decimal antes de analizar, pero si está trabajando con números arbitrarios, como números con formato bonito como 1,234,567, entonces ese enfoque no funciona.

David Kitzinger
fuente
0

No necesita reemplazar los puntos (respectivamente las comas), solo especifique la entrada 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"));
mortal
fuente
0

Si desea verificar y convertir el valor del exponente, use este

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

Espero que esto ayude a alguien.

RAM
fuente