Проверять число с плавающей запятой, используя RegEx в С#

Я пытаюсь сделать только числовое число TextBox в WPF, и у меня есть для него этот код:

void NumericTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !IsValidInput(e.Text);
}

private bool IsValidInput(string p)
{
    switch (this.Type)
    {
        case NumericTextBoxType.Float:
            return Regex.Match(p, "^[0-9]*[.][0-9]*$").Success;
        case NumericTextBoxType.Integer:                    
        default:
            return Regex.Match(p, "^[0-9]*$").Success;                    
    }
}

// And also this!
public enum NumericTextBoxType
{
    Integer = 0, 
    Float = 1
}

Когда я устанавливаю тип Integer, он работает хорошо, но для Float это не так.

Я могу использовать так много элементов управления NumericTextBox, но мне было интересно, почему этот не работает?

Ответ 1

Попробуйте следующее:

@"^[0-9]*(?:\.[0-9]*)?$"

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

Если вам нужно обрабатывать отрицательные значения, вы можете добавить -? до первого [0-9] в каждом шаблоне.

Обновление

Протестировано следующим образом:

var regex = new Regex(@"^[0-9]*(?:\.[0-9]*)?$");
Console.WriteLine(new bool[] {regex.IsMatch("blah"),
                              regex.IsMatch("12"),
                              regex.IsMatch(".3"),
                              regex.IsMatch("12.3"),
                              regex.IsMatch("12.3.4")});

приводит к

False 
True 
True 
True 
False 

Ответ 2

Я настоятельно рекомендую использовать метод Double.TryParse() вместо проверки регулярных выражений. Используя TryParse(), ваше приложение будет немного более универсальным с точки зрения культуры. Когда текущая культура изменяется, TryParse() будет анализироваться без проблем. Также методы TryParse(), которые, как полагают, не имеют ошибок, поскольку они были протестированы сообществом .net:).

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

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

private bool IsValidInput(string p)
{
    switch (this.Type)
    {
        case NumericTextBoxType.Float:
            double doubleResult;
            return double.TryParse(p, out doubleResult);
        case NumericTextBoxType.Integer:                    
        default:
            int intResult;
            return int.TryParse(p, out intResult);
    }
}

Вы даже можете добавить свои собственные методы расширения, чтобы сделать парсинг более элегантным.

public static double? TryParseInt(this string source)
{
    double result;
    return double.TryParse(source, out result) ? result : (double?)null;
}

// usage
bool ok = source.TryParseInt().HasValue;

Ответ 3

Проверьте статические методы TryParse, которые вы найдете в double, float и int.

Они возвращают true, если строка может быть проанализирована (методом Parse).

Ответ 4

[-+]?\d+(.\d+)?

Самое простое регулярное выражение для float. Это не соответствует случаям "123." или '.123'.

Кроме того, вы должны посмотреть на контекстную культуру:

CultureInfo ci = CultureInfo.CurrentCulture;
var decimalSeparator = ci.NumberFormat.NumberDecimalSeparator;
var floatRegex = string.Format(@"[-+]?\d+({0}\d+)?", decimalSeparator);

Ответ 5

Я попробовал решение, одобренное выше, обнаружил, что он не сработает, если пользователь вводит только точку @"^[0-9]*(?:\.[0-9]*)?$".

Итак, я изменил его на:

@"^[0-9]*(?:\.[0-9]+)?$"

Ответ 6

Это код, который я придумал, смешивая ответы от @Andrew Cooper и @Ramesh. Добавлен код словаря, поэтому любое тело, думающее о тестировании кода, может запускать как можно больше тестовых примеров.

//greater than or equal to zero floating point numbers
Regex floating = new Regex(@"^[0-9]*(?:\.[0-9]+)?$");
        Dictionary<string, bool> test_cases = new Dictionary<string, bool>();
        test_cases.Add("a", floating.IsMatch("a"));
        test_cases.Add("a.3", floating.IsMatch("a.3"));
        test_cases.Add("0", floating.IsMatch("0"));
        test_cases.Add("-0", floating.IsMatch("-0"));
        test_cases.Add("-1", floating.IsMatch("-1"));
        test_cases.Add("0.1", floating.IsMatch("0.1"));
        test_cases.Add("0.ab", floating.IsMatch("0.ab"));

        test_cases.Add("12", floating.IsMatch("12"));
        test_cases.Add(".3", floating.IsMatch(".3"));
        test_cases.Add("12.3", floating.IsMatch("12.3"));
        test_cases.Add("12.3.4", floating.IsMatch("12.3.4"));
        test_cases.Add(".", floating.IsMatch("."));

        test_cases.Add("0.3", floating.IsMatch("0.3"));
        test_cases.Add("12.31252563", floating.IsMatch("12.31252563"));
        test_cases.Add("-12.31252563", floating.IsMatch("-12.31252563"));

        foreach (KeyValuePair<string, bool> pair in test_cases)
        {
            Console.WriteLine(pair.Key.ToString() + "  -  " + pair.Value);
        }