c # Почему я получаю двойное значение без десятичного числа (преобразование из объекта в double) [дубликат]

Если вы загружаете 32-разрядную версию вашей DLL с 64-разрядной JRE, у вас может возникнуть проблема. Это был мой случай.

184
задан CodeCaster 16 November 2013 в 20:01
поделиться

14 ответов

        var doublePattern = @"(?<integer>[0-9]+)(?:\,|\.)(?<fraction>[0-9]+)";
        var sourceDoubleString = "03444,44426";
        var match = Regex.Match(sourceDoubleString, doublePattern);

        var doubleResult = match.Success ? double.Parse(match.Groups["integer"].Value) + (match.Groups["fraction"].Value == null ? 0 : double.Parse(match.Groups["fraction"].Value) / Math.Pow(10, match.Groups["fraction"].Value.Length)): 0;
        Console.WriteLine("Double of string '{0}' is {1}", sourceDoubleString, doubleResult);
0
ответ дан Alexander 22 August 2018 в 08:55
поделиться

Посмотрите, каждый ответ выше, который предлагает записать замену строки постоянной строкой, может быть ошибочным. Зачем? Потому что вы не уважаете региональные настройки Windows! Windows гарантирует, что пользователь имеет право устанавливать любой разделитель. S / He может открыть панель управления, перейти в область области, нажать на продвинутый и изменить символ в любое время. Даже во время вашей программы. Подумайте об этом. Хорошее решение должно знать об этом.

Итак, сначала вам придется спросить себя, откуда этот номер, что вы хотите разобрать. Если это происходит от ввода в .NET Framework без проблем, потому что он будет в том же формате. Но, возможно, это происходило извне, возможно, с внешнего сервера, возможно, из старой БД, которая поддерживает только свойства строки. Там администратор db должен был дать правило, в котором формат должен быть сохранен. Если вы знаете, например, что это будет американская БД с американским форматом, вы можете использовать этот фрагмент кода:

CultureInfo usCulture = new CultureInfo("en-US");
NumberFormatInfo dbNumberFormat = usCulture.NumberFormat;
decimal number = decimal.Parse(db.numberString, dbNumberFormat);

Это будет прекрасно работать в любой точке мира. И, пожалуйста, не используйте «Convert.ToXxxx». Класс «Конвертировать» считается только базой для конверсий в любом направлении. Кроме того: вы также можете использовать аналогичный механизм для DateTimes.

8
ответ дан AndresRohrAtlasInformatik 22 August 2018 в 08:55
поделиться
  • 1
    Согласовано! Попытка вручную реализовать функции Культуры в конечном итоге приведет к тому, что вы не ожидали, и большой головной боли. Пусть .NET справится с этим должным образом. – Khalos 4 July 2015 в 16:48
  • 2
    большая проблема заключается в том, что пользователи используют десятичный разделитель, который не считается десятичным разделителем для его культурных настроек – EdmundYeung99 30 September 2015 в 01:28
System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CurrentCulture;

string _pos = dblstr.Replace(".",
    ci.NumberFormat.NumberDecimalSeparator).Replace(",",
        ci.NumberFormat.NumberDecimalSeparator);

double _dbl = double.Parse(_pos);
-1
ответ дан Arnon Zilca 22 August 2018 в 08:55
поделиться
Double.Parse("3,5".Replace(',', '.'), CultureInfo.InvariantCulture)

Заменить запятую точкой до разбора. Полезно в странах с запятой в качестве десятичного разделителя. Подумайте об ограничении ввода пользователем (при необходимости) в одну запятую или точку.

8
ответ дан Baluda 22 August 2018 в 08:55
поделиться
  • 1
    Гораздо более правильный ответ, чем тот, который имеет +133 голосов ... Он позволяет жить в обеих системах с помощью & quot ;, & quot; или "." десятичный разделитель ... – Badiboy 11 June 2014 в 16:14
  • 2
    @Badiboy вы можете объяснить, что не так с этим ответом? Как я понимаю, InvariantCulture всегда имеет. как десятичный разделитель. Поэтому он должен работать для обеих систем. – AlexP11223 26 June 2014 в 21:10
  • 3
    @ Alex11223 Вы правы. Вот почему я сказал, что этот ответ лучше, чем более популярный. PS: Дружелюбный говорящий этот код также потерпит неудачу, если у вас есть & quot ;, & quot; как СПИСОК СЕПАРАТОРОВ (т. е. 1 234 560,01), но я не знаю, как решить это вообще. :) – Badiboy 27 June 2014 в 05:56
  • 4
    Это не очень хороший ответ, потому что в некоторых культурах это разделитель тысяч и может использоваться. Если вы замените его на точку, тогда вы получите несколько точек, и анализ не будет выполнен: Double.Parse ((12345.67) .ToString («N», новая CultureInfo («en»)). Замените (',', '.'), CultureInfo.InvariantCulture), потому что (12345.67) .ToString ("N", новая CultureInfo ("en")). Заменить (',', '.') Будет отформатирован как "12.345.67" ; – codingdave 27 February 2018 в 12:18

Вместо того, чтобы указывать локаль во всех разборах, я предпочитаю устанавливать широко распространенный язык приложения, хотя, если строковые форматы не соответствуют друг другу, это может не сработать.

CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("pt-PT");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("pt-PT");

Определение это в начале вашего заявления сделает все двойные парсы ожидающими запятой как десятичным разделителем. Вы можете установить соответствующий языковой стандарт, чтобы разделитель десятичных и тысяч символов соответствовал строкам, которые вы обрабатываете.

0
ответ дан BlunT 22 August 2018 в 08:55
поделиться

Я думаю, что это лучший ответ:

public static double StringToDouble(string toDouble)
{
    toDouble = toDouble.Replace(",", "."); //Replace every comma with dot

    //Count dots in toDouble, and if there is more than one dot, throw an exception.
    //Value such as "123.123.123" can't be converted to double
    int dotCount = 0;
    foreach (char c in toDouble) if (c == '.') dotCount++; //Increments dotCount for each dot in toDouble
    if (dotCount > 1) throw new Exception(); //If in toDouble is more than one dot, it means that toCount is not a double

    string left = toDouble.Split('.')[0]; //Everything before the dot
    string right = toDouble.Split('.')[1]; //Everything after the dot

    int iLeft = int.Parse(left); //Convert strings to ints
    int iRight = int.Parse(right);

    //We must use Math.Pow() instead of ^
    double d = iLeft + (iRight * Math.Pow(10, -(right.Length)));
    return d;
}
-2
ответ дан Endorphinex 22 August 2018 в 08:55
поделиться
  • 1
    Объяснение кода и предоставление более подробной информации было бы полезно. – Charlie Fish 26 September 2016 в 20:24
  • 2
    Что объяснить здесь? Все в комментариях – Endorphinex 26 September 2016 в 20:46
string testString1 = "2,457";
string testString2 = "2.457";    
double testNum = 0.5;
char decimalSepparator;
decimalSepparator = testNum.ToString()[1];

Console.WriteLine(double.Parse(testString1.Replace('.', decimalSepparator).Replace(',', decimalSepparator)));
Console.WriteLine(double.Parse(testString2.Replace('.', decimalSepparator).Replace(',', decimalSepparator)));
2
ответ дан Martin 22 August 2018 в 08:55
поделиться
  • 1
    Это не будет работать для стран, которые используют тысячу разделителей. – noggin182 18 February 2014 в 18:03
double.Parse("3.5", CultureInfo.InvariantCulture)
350
ответ дан Mehrdad Afshari 22 August 2018 в 08:55
поделиться
  • 1
    Ну, XmlConvert на самом деле не предназначен для использования для анализа одного двойного значения в коде. Я предпочитаю использовать double.Parse или Convert.ToDouble, которые делают мое намерение очевидным. – Mehrdad Afshari 30 August 2009 в 22:29
  • 2
    Это означает, что doulble.Parse использует культуру по умолчанию, которая не может содержать точку в виде десятичной точки? – Ahmed Said 30 August 2009 в 23:32
  • 3
    Он использует текущую культуру потока, в котором он работает. – Mehrdad Afshari 30 August 2009 в 23:40
  • 4
    если конвертировать 12345678.12345678, он тоже преобразует 12345678.123457 – PUG 2 December 2011 в 18:18
  • 5
    не работал для меня: пропускает запятую и возвращает, а int как double – fnc12 8 July 2015 в 15:44

Трудно не указывать, какой десятичный разделитель искать, но если вы это делаете, это то, что я использую:

    public static double Parse(string str, char decimalSep)
    {
        string s = GetInvariantParseString(str, decimalSep);
        return double.Parse(s, System.Globalization.CultureInfo.InvariantCulture);
    }

    public static bool TryParse(string str, char decimalSep, out double result)
    {
        // NumberStyles.Float | NumberStyles.AllowThousands got from Reflector
        return double.TryParse(GetInvariantParseString(str, decimalSep), NumberStyles.Float | NumberStyles.AllowThousands, System.Globalization.CultureInfo.InvariantCulture, out result);
    }

    private static string GetInvariantParseString(string str, char decimalSep)
    {
        str = str.Replace(" ", "");

        if (decimalSep != '.')
            str = SwapChar(str, decimalSep, '.');

        return str;
    }
    public static string SwapChar(string value, char from, char to)
    {
        if (value == null)
            throw new ArgumentNullException("value");

        StringBuilder builder = new StringBuilder();

        foreach (var item in value)
        {
            char c = item;
            if (c == from)
                c = to;
            else if (c == to)
                c = from;

            builder.Append(c);
        }
        return builder.ToString();
    }

    private static void ParseTestErr(string p, char p_2)
    {
        double res;
        bool b = TryParse(p, p_2, out res);
        if (b)
            throw new Exception();
    }

    private static void ParseTest(double p, string p_2, char p_3)
    {
        double d = Parse(p_2, p_3);
        if (d != p)
            throw new Exception();
    }

    static void Main(string[] args)
    {
        ParseTest(100100100.100, "100.100.100,100", ',');
        ParseTest(100100100.100, "100,100,100.100", '.');
        ParseTest(100100100100, "100.100.100.100", ',');
        ParseTest(100100100100, "100,100,100,100", '.');
        ParseTestErr("100,100,100,100", ',');
        ParseTestErr("100.100.100.100", '.');
        ParseTest(100100100100, "100 100 100 100.0", '.');
        ParseTest(100100100.100, "100 100 100.100", '.');
        ParseTest(100100100.100, "100 100 100,100", ',');
        ParseTest(100100100100, "100 100 100,100", '.');
        ParseTest(1234567.89, "1.234.567,89", ',');    
        ParseTest(1234567.89, "1 234 567,89", ',');    
        ParseTest(1234567.89, "1 234 567.89",     '.');
        ParseTest(1234567.89, "1,234,567.89",    '.');
        ParseTest(1234567.89, "1234567,89",     ',');
        ParseTest(1234567.89, "1234567.89",  '.');
        ParseTest(123456789, "123456789", '.');
        ParseTest(123456789, "123456789", ',');
        ParseTest(123456789, "123.456.789", ',');
        ParseTest(1234567890, "1.234.567.890", ',');
    }

Это должно работать с любой культурой. Он корректно не разбирает строки, содержащие более одного разделителя, в отличие от реализаций, заменяющих вместо swap.

0
ответ дан osexpert 22 August 2018 в 08:55
поделиться

Умножьте число, а затем разделите его на то, что вы его умножали раньше.

Например,

perc = double.Parse("3.555)*1000;
result = perc/1000
15
ответ дан Peter Mortensen 22 August 2018 в 08:55
поделиться
  • 1
    1.234.567.890 вернется 1234567.890 – Dan Vogel 23 August 2011 в 18:39
  • 2
    Я не пробовал, но если вы выполняете приложение в разных SO SO, этот код не будет делать трюк, я думаю: / – Dani bISHOP 30 May 2012 в 16:59
  • 3
    Re: "... потому что в Канаде мы пишем 3,5 вместо 3.5" Вы уверены в этом? Согласно Десятичная метка : «Страны, где точка». используется как десятичная метка, включая ... Канада (при использовании английского) & quot; . Разве это не больше об использовании французской версии Windows? – Peter Mortensen 21 November 2016 в 17:57
  • 4
    Baybe из-за французской версии. В montreal пишем 3,5 не 3,5 – Malus Jan 23 November 2016 в 04:43
  • 5
    Итак, согласно вашей логике, всегда только 1 из них верны? – batmaci 9 October 2017 в 00:56
  • 6
    Посмотрите на it – Malus Jan 9 October 2017 в 19:19
  • 7
    Все еще есть ошибка. Для входной строки, такой как GetDouble ("10 ,,,,,,,, 0", 0.0). Упомянутая функция возвращает 100. – Krivers 14 August 2018 в 03:56

Обычно я использую функцию мультикультуры для синтаксического анализа пользовательского ввода, в основном потому, что, если кто-то используется для numpad и использует культуру, которая использует запятую в качестве разделителя десятичных чисел, этот человек будет использовать точку numpad вместо запятая.

public static double GetDouble(string value, double defaultValue)
{
    double result;

    //Try parsing in the current culture
    if (!double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.CurrentCulture, out result) &&
        //Then try in US english
        !double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result) &&
        //Then in neutral language
        !double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out result))
    {
        result = defaultValue;
    }

    return result;
}

Остерегайтесь, однако, комментарии @nikie верны. Для моей защиты я использую эту функцию в контролируемой среде, где я знаю, что культура может быть en-US, en-CA или fr-CA. Я использую эту функцию, потому что на французском языке мы используем запятую как разделитель десятичной дроби, но любой, кто когда-либо работал в сфере финансов, всегда будет использовать десятичный разделитель на numpad, но это точка, а не запятая. Поэтому даже в культуре fr-CA мне нужно проанализировать число, которое будет иметь точку в качестве разделителя десятичных чисел.

61
ответ дан Pierre-Alain Vigeant 22 August 2018 в 08:55
поделиться
  • 1
    Я не уверен, что это хорошая идея. Вы не можете достоверно разобрать двойной, если вы не знаете культуру: в Германии двойные значения могут содержать «.», Но они считаются тысячами-разделителями. Таким образом, в случае с Legate GetDouble («3.5») вернет 35 в немецком языке и 3.5 в среде en-us. – Niki 15 October 2009 в 14:58
  • 2
    Нет, Пьер Ален прав, поскольку это точно так же, как написано. Если ваша культура говорит «точка - это тысяча», разделитель, затем "3,5" рассматривается как "35" и это хорошо. Однако, если вы культивируете как никакие правила для «точки», тогда символ анализируется как десятичная точка, и он также работает. Я бы не стал пытаться использовать enUS-культуру, но это личный выбор. – xryl669 10 April 2013 в 16:33
  • 3
    Если вы используете numpad в культуре с запятой, точечная клавиша будет установлена ​​запятая. – CrazyBaran 25 August 2017 в 09:59
  • 4
    Десятичный разделитель numpad зависит от раскладки клавиатуры (а не региональных настроек - по крайней мере, в Windows 7) (я использую венгерский для написания текста, сообщений электронной почты ... и en-US для написания кода, так что это может быть либо точка или запятая. Я также использую настраиваемые региональные настройки, в которых я изменил разделитель десятичных чисел от ',' до '.' и разделителя списков от ';' до ','. Знаете, вызывают csv ... Удачи нам всем писать несколько -культурные приложения;) – Steven Spark 22 June 2018 в 13:15

Трюк заключается в использовании инвариантной культуры, чтобы разобрать точку во всех культурах.

double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.NumberFormatInfo.InvariantInfo);
16
ответ дан Yakeen 22 August 2018 в 08:55
поделиться

Ниже ниже эффективность, но я использую эту логику. Это допустимо, только если у вас есть две цифры после десятичной точки.

double val;

if (temp.Text.Split('.').Length > 1)
{
    val = double.Parse(temp.Text.Split('.')[0]);

    if (temp.Text.Split('.')[1].Length == 1)
        val += (0.1 * double.Parse(temp.Text.Split('.')[1]));
    else
        val += (0.01 * double.Parse(temp.Text.Split('.')[1]));
}
else
    val = double.Parse(RR(temp.Text));
15
ответ дан Peter Mortensen 22 August 2018 в 08:55
поделиться
  • 1
    1.234.567.890 вернется 1234567.890 – Dan Vogel 23 August 2011 в 18:39
  • 2
    Я не пробовал, но если вы выполняете приложение в разных SO SO, этот код не будет делать трюк, я думаю: / – Dani bISHOP 30 May 2012 в 16:59
  • 3
    Re: "... потому что в Канаде мы пишем 3,5 вместо 3.5" Вы уверены в этом? Согласно Десятичная метка : «Страны, где точка». используется как десятичная метка, включая ... Канада (при использовании английского) & quot; . Разве это не больше об использовании французской версии Windows? – Peter Mortensen 21 November 2016 в 17:57
  • 4
    Baybe из-за французской версии. В montreal пишем 3,5 не 3,5 – Malus Jan 23 November 2016 в 04:43
  • 5
    Итак, согласно вашей логике, всегда только 1 из них верны? – batmaci 9 October 2017 в 00:56
  • 6
    Посмотрите на it – Malus Jan 9 October 2017 в 19:19
  • 7
    Все еще есть ошибка. Для входной строки, такой как GetDouble ("10 ,,,,,,,, 0", 0.0). Упомянутая функция возвращает 100. – Krivers 14 August 2018 в 03:56
17
ответ дан Peter Mortensen 5 November 2018 в 06:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: