Analizar un número de notación exponencial
-
28-09-2019 - |
Pregunta
Tengo que 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 emite un error
Solución
Es un número de coma flotante, hay que decirle que:
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Otros consejos
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 está soportado por defecto - el valor por defecto es utilizar NumberStyles.Number
, que utiliza el AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint y estilos AllowThousands. Posiblemente es variable; especificando un exponente es relativamente raro, supongo.
Además de especificar los NumberStyles lo recomiendo que utilice el decimal.TryParse función, 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.Any que podría utilizar un conjunto específico si está seguro de sus formatos. por ejemplo:
NumberStyles.AllowExponent | NumberStyles.Float
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Sea cauteloso sobre la respuesta seleccionada: hay una sutileza que especifica System.Globalization.NumberStyles.Float en Decimal.Parse lo que podría conducir a un Sistema. FormatException debido a que su sistema podría estar esperando un número formateado con '' en lugar de ''.
Por ejemplo, en la notación francés, "1.2345E-02" no es válido, tiene que convertirlo en "1,2345E-02" en primer lugar.
En conclusión, el uso de algo en la línea de:
Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);
he encontrado que pasa en NumberStyles.Float
, en algunos casos, los cambios de las reglas por las que la cadena se procesa y resulta en una salida diferente de NumberStyles.Number
(las reglas predeterminadas utilizadas por decimal.Parse
).
Por ejemplo, el siguiente código generará un FormatException
en 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
Me gustaría recomendar el uso del NumberStyles.Number | NumberStyles.AllowExponent
de entrada, ya que esto permitirá números exponenciales y todavía procesará la cadena bajo las reglas 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
Para responder a la pregunta del cartel, la respuesta correcta debería ser en su lugar:
decimal x = decimal.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Console.WriteLine(x);
Advertencia sobre el uso de NumberStyles.Any:
"6.33E + 03" conversos al 6330 como se esperaba. En alemán, los decimales se representan por comas, pero 6,33E + 03 convertidos a 633000! Esto es un problema para mis clientes, como la cultura que genera los datos no se conoce y puede ser diferente de la cultura que está operando en los datos. En mi caso, siempre tengo la notación científica, por lo que siempre se puede sustituir por comas a punto decimal antes del análisis, pero si se está trabajando con números arbitrarios, como los números bastante con formato similar a 1.234.567 continuación, ese enfoque no funciona.
no es necesario reemplazar los puntos (respectivamente las comas) acaba de especificar el IFormatProvider de entrada:
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"));
Si desea comprobar y convertir el uso de este valor del exponente
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.