Разобрать число из экспоненциальной записи


85

Мне нужно преобразовать строку «1.2345E-02» (число, выраженное в экспоненциальной записи) в десятичный тип данных, но Decimal.Parse("1.2345E-02")просто выдает ошибку

Ответы:


170

Это число с плавающей запятой, вы должны сказать ему, что:

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

49

Работает, если указать NumberStyles.Float:

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

Я не совсем уверен, почему это не поддерживается по умолчанию - по умолчанию NumberStyles.Numberиспользуется стиль AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint и AllowThousands. Возможно, это связано с производительностью; Я полагаю, что указание экспоненты относительно редко.


Я пытаюсь заставить это работать с двойным, но, похоже, это не так. Не уверен, почему это не могло ..?
JanT 05

@JanT: Не имея дополнительной информации, кроме «не будет» и «не может», я не могу больше помочь. Я предлагаю вам задать новый вопрос с более подробным описанием того, что вы пробовали и что именно произошло.
Джон Скит

Я попытался запустить код, как в вашем ответе, но вместо десятичного числа использовал double. Но обходной путь уже нашел. Приветствия
JANT

1
@JanT Было бы неплохо, если бы вы могли поделиться своим обходным путем. У меня точно такая же проблема, и я могу использовать информацию. Благодарность!
Рик

@RickGlimmer: Я не уверен, откуда вы знаете, что ваша проблема такая же, как у JanT, учитывая, что они никогда не предоставляли подробностей о том, что они пытались сделать. Замена decimalна doubleв моем коде отлично работает для меня, как я и ожидал. Если бы вы могли предоставить подробную информацию о том, что вы пытаетесь сделать, код, который вы используете, и результат, вам было бы намного легче помочь.
Джон Скит

35

В дополнение к указанию NumberStyles я бы рекомендовал вам использовать функцию decimal.TryParse, например:

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

В качестве альтернативы NumberStyles.Any вы можете использовать определенный набор, если вы уверены в своих форматах. например:

NumberStyles.AllowExponent | NumberStyles.Float

1
Но нет необходимости использовать Float с AllowExponent, потому что Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent
Лукаш Кмох

@ LukášKmoch Вы правы. Сила привычки, поскольку другие (кроме Any) ее не включают. Однако не повредит выполнить дополнительное ИЛИ.
Sverrir Sigmundarson


8

Будьте осторожны с выбранным ответом: существует тонкость, указывающая System.Globalization.NumberStyles.Float в Decimal.Parse, что может привести к System.FormatException, потому что ваша система может ожидать числа, отформатированного с помощью ',' вместо ''.

Например, во французской нотации "1.2345E-02" недопустимо, вы должны сначала преобразовать его в "1,2345E-02".

В заключение используйте что-нибудь вроде:

Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);

1
Вы абсолютно правы. Не понимаю, почему никто об этом не поднял.
Карлес

10
Лучше используйте CultureInfo.InvariantCulture в качестве третьего параметра Parse
Андрей Козачук

3

Я обнаружил, что передача в NumberStyles.Floatнекоторых случаях изменяет правила, по которым обрабатывается строка, и приводит к другому выводу из NumberStyles.Number(правила по умолчанию, используемыеdecimal.Parse ).

Например, следующий код сгенерирует на FormatExceptionмоей машине:

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

Я бы рекомендовал использовать ввод NumberStyles.Number | NumberStyles.AllowExponent, так как это позволит использовать экспоненциальные числа и по-прежнему будет обрабатывать строку в соответствии с 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

Чтобы ответить на вопрос автора, правильный ответ должен быть таким:

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

1

Предупреждение об использовании NumberStyles.Any:

«6.33E + 03» преобразуется в 6330, как и ожидалось. На немецком языке десятичные точки представлены запятыми, но 6,33E + 03 преобразуется в 633000! Это проблема для моих клиентов, так как культура, генерирующая данные, неизвестна и может отличаться от культуры, которая работает с данными. В моем случае у меня всегда есть научная нотация, поэтому я всегда могу заменить запятую на десятичную точку перед синтаксическим анализом, но если вы работаете с произвольными числами, такими как хорошо отформатированные числа, такие как 1,234,567, тогда этот подход не работает.


0

Вам не нужно заменять точки (соответственно запятые), просто укажите входной 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

Если вы хотите проверить и преобразовать значение экспоненты, используйте это

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

Надеюсь, это кому-то поможет.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.