универсальный парсинг строк в плавание

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

Как был бы Вы реализовывать такой floatparse (строка) функция?

Я попробовал этого:

    try
    {
        d = float.Parse(s);
    }
    catch
    {
        try
        {
            d = float.Parse(s.Replace(".", ","));
        }
        catch
        {
            d = float.Parse(s.Replace(",", "."));
        }
    }

Это не работает. И когда я отлаживаю, оказывается, что это анализирует его, неправильно в первый раз думая, что это - разделитель для тысяч (как 100.000.000,0).

Я - новичок в C#, так надо надеяться, существует менее сверхсложное решение затем это :-)

Люди NB: попытка использовать обоих '.' и'', в ПК с различными настройками разделителя.

5
задан mskfisher 5 June 2012 в 16:05
поделиться

3 ответа

Если вы уверены, что никто не использует разделители разрядов, вы можете сначала заменить:

string s = "1,23";  // or s = "1.23";

s = s.Replace(',', '.');
double d = double.Parse(s, CultureInfo.InvariantCulture);

Общий шаблон будет следующим:

  • сначала попробуйте очистить и нормализовать. Нравится Replace (otherChar, myChar).
  • попытайтесь определить формат, возможно, используя RegEx, и используйте целевое преобразование. Как подсчет. и, чтобы угадать, используются ли разделители тысяч.
  • попробуйте несколько форматов по порядку с помощью TryParse. Не используйте и исключения для этого.
10
ответ дан 18 December 2019 в 14:41
поделиться

Я бы сделал что-то вроде этого

float ConvertToFloat(string value)
{
    float result;

    var converted  = float.TryParse(value, out result);

    if (converted) return result;

    converted = float.TryParse(value.Replace(".", ",")), 
                               out result);

    if (converted) return result;

    return float.NaN;
}

В этом случае следующее вернет правильные данные

        Console.WriteLine(ConvertToFloat("10.10").ToString());
        Console.WriteLine(ConvertToFloat("11,0").ToString());
        Console.WriteLine(ConvertToFloat("12").ToString());
        Console.WriteLine(ConvertToFloat("1 . 10").ToString());

Returns

10,1
11
12
NaN

В этом случае, если не получится преобразовать, вы хотя бы будете знать, что это не число. Это безопасный способ преобразования.

Вы также можете использовать следующую перегрузку

float.TryParse(value,
            NumberStyles.Currency,
            CultureInfo.CurrentCulture,
            out result)

На этом тестовом коде:

Console.WriteLine(ConvertToFloat("10,10").ToString());
Console.WriteLine(ConvertToFloat("11,0").ToString());
Console.WriteLine(ConvertToFloat("12").ToString());
Console.WriteLine(ConvertToFloat("1 . 10").ToString());
Console.WriteLine(ConvertToFloat("100.000,1").ToString());

Он возвращает следующее

10,1
11
12
110
100000,1

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

Это будет выглядеть следующим образом

float ConvertToFloat(string value)
{
    float result;

    var converted = float.TryParse(value,
                                    out result);


    if (converted) return result;

    converted = float.TryParse(value.Replace(".", ","),
                                out result);

    if (converted) return result;

    converted = float.TryParse(value,
                                    NumberStyles.Currency,
                                    CultureInfo.CurrentCulture,
                                    out result);

    return converted ? result : float.NaN;
}

Где следующее

Console.WriteLine(ConvertToFloat("10,10").ToString());
Console.WriteLine(ConvertToFloat("11,0").ToString());
Console.WriteLine(ConvertToFloat("12").ToString());
Console.WriteLine(ConvertToFloat("1 . 10").ToString());
Console.WriteLine(ConvertToFloat("100.000,1").ToString());
Console.WriteLine(ConvertToFloat("asdf").ToString());

Возвращает

10,1
11
12
110
100000,1
NaN
1
ответ дан 18 December 2019 в 14:41
поделиться

Парсинг использует настройки CultureInfo.CurrentCulture, которые отражают язык и формат чисел, выбранный пользователем через Regional Settings. Если ваши пользователи вводят десятичные числа, соответствующие языку, который они выбрали для своих компьютеров, у вас не должно возникнуть проблем с использованием старого доброго double.Parse(). Если пользователь установит свою локаль на греческий язык и наберет "8,5", double.Parse("8,5") вернет 8,5. Если он напечатает "8,5", разбор вернет 85.

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

Другой, несколько более жесткий вариант - запретить группирующий символ для ввода чисел в вашем приложении, отменив его в событии KeyDown ваших текстовых полей. Вы можете получить числовые и группирующие символы из свойства CultureInfo.CurrentCulture.NumberFormat.

Попытка заменить десятичные и группирующие символы обречена на неудачу, поскольку она зависит от знания во время компиляции, какой тип разделителя будет использовать пользователь. Если бы вы знали это, вы могли бы просто разобрать число, используя CultureInfo в сознании пользователя. К сожалению, User.Brain.CultureInfo пока не является частью .NET framework :P

2
ответ дан 18 December 2019 в 14:41
поделиться
Другие вопросы по тегам:

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