我如何获得一个TextBox只接受WPF中的数字输入?


334

我希望接受数字和小数点,但没有符号。

我看过使用Windows窗体的NumericUpDown控件的示例,以及Microsoft的NumericUpDown自定义控件的示例。但是到目前为止,似乎NumericUpDown(是否受WPF支持)将无法提供我想要的功能。我的应用程序的设计方式是,没有一个头脑正确的人会想弄乱箭头。在我的应用程序上下文中,它们没有任何实际意义。

因此,我正在寻找一种简单的方法来使标准WPF TextBox仅接受我想要的字符。这可能吗?实用吗?

Answers:


417

添加预览文本输入事件。像这样:<TextBox PreviewTextInput="PreviewTextInput" />

然后在该设置内,e.Handled如果不允许输入文本。e.Handled = !IsTextAllowed(e.Text);

我在IsTextAllowed方法中使用了一个简单的正则表达式,以查看是否应该允许他们键入内容。就我而言,我只想允许数字,点和破折号。

private static readonly Regex _regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
private static bool IsTextAllowed(string text)
{
    return !_regex.IsMatch(text);
}

如果你想防止不正确的数据勾起来了的粘贴DataObject.Pasting事件DataObject.Pasting="TextBoxPasting"在这里(代码摘录):

// Use the DataObject.Pasting Handler 
private void TextBoxPasting(object sender, DataObjectPastingEventArgs e)
{
    if (e.DataObject.GetDataPresent(typeof(String)))
    {
        String text = (String)e.DataObject.GetData(typeof(String));
        if (!IsTextAllowed(text))
        {
            e.CancelCommand();
        }
    }
    else
    {
        e.CancelCommand();
    }
}

5
如果这很重要,则您的正则表达式不允许使用科学计数法(1e5)。
罗恩·沃霍尔奇

14
请注意,此答案仅检查您键入的内容,因此您可以输入3-.3
David Sykes

153
答案的重点不是指定完美的Regex,而是显示如何使用WPF来过滤某人键入的内容。

27
[空格]不会触发PreviewTextInput事件。
peterG

5
类似的事情double.TryParse()可能用相同数量的行来实现,并且更加灵活。
托马斯·韦勒

190

事件处理程序正在预览文本输入。在这里,仅当正则表达式不是数字时,它才与文本输入匹配,然后才将其不输入文本框。

如果只需要字母,则将正则表达式替换为[^a-zA-Z]

XAML

<TextBox Name="NumberTextBox" PreviewTextInput="NumberValidationTextBox"/>

XAML.CS文件

using System.Text.RegularExpressions;
private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
{
    Regex regex = new Regex("[^0-9]+");
    e.Handled = regex.IsMatch(e.Text);
}

1
事件处理程序是预览文本输入。这里,正则表达式仅在不是数字的情况下才与文本输入匹配,因此不会在输入文本框中输入正则表达式。如果只需要字母,则将正则表达式替换为[^ a-zA-Z]。
基什(Kishor)2012年

数字,小数和运算符呢?
詹森·埃伯西

请在其他STATIC类中声明并应用于文本框时让我知道如何使用它?
SHEKHAR SHETE

3
我喜欢这个答案,而不是简单简短的答案。实际答案需要两种方法才能获得相同的结果。
2015年

1
@Jagd建议的答案是更好的关注点分离。但是,您也可以在此验证中设置尽可能多的文本框。只需添加PreviewTextInput =“ NumberValidationTextBox”。(就像其他答案一样!)
Sliver

84

我使用了这里已经存在的一些内容,并通过一种行为将自己的想法加到了上面,这样我就不必在大量视图中传播此代码了。

public class AllowableCharactersTextBoxBehavior : Behavior<TextBox>
{
    public static readonly DependencyProperty RegularExpressionProperty =
         DependencyProperty.Register("RegularExpression", typeof(string), typeof(AllowableCharactersTextBoxBehavior),
         new FrameworkPropertyMetadata(".*"));
    public string RegularExpression
    {
        get
        {
            return (string)base.GetValue(RegularExpressionProperty);
        }
        set
        {
            base.SetValue(RegularExpressionProperty, value);
        }
    }

    public static readonly DependencyProperty MaxLengthProperty =
        DependencyProperty.Register("MaxLength", typeof(int), typeof(AllowableCharactersTextBoxBehavior),
        new FrameworkPropertyMetadata(int.MinValue));
    public int MaxLength
    {
        get
        {
            return (int)base.GetValue(MaxLengthProperty);
        }
        set
        {
            base.SetValue(MaxLengthProperty, value);
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewTextInput += OnPreviewTextInput;
        DataObject.AddPastingHandler(AssociatedObject, OnPaste);
    }

    private void OnPaste(object sender, DataObjectPastingEventArgs e)
    {
        if (e.DataObject.GetDataPresent(DataFormats.Text))
        {
            string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

            if (!IsValid(text, true))
            {
                e.CancelCommand();
            }
        }
        else
        {
            e.CancelCommand();
        }
    }

    void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
    {
        e.Handled = !IsValid(e.Text, false);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewTextInput -= OnPreviewTextInput;
        DataObject.RemovePastingHandler(AssociatedObject, OnPaste);
    }

    private bool IsValid(string newText, bool paste)
    {
        return !ExceedsMaxLength(newText, paste) && Regex.IsMatch(newText, RegularExpression);
    }

    private bool ExceedsMaxLength(string newText, bool paste)
    {
        if (MaxLength == 0) return false;

        return LengthOfModifiedText(newText, paste) > MaxLength;
    }

    private int LengthOfModifiedText(string newText, bool paste)
    {
        var countOfSelectedChars = this.AssociatedObject.SelectedText.Length;
        var caretIndex = this.AssociatedObject.CaretIndex;
        string text = this.AssociatedObject.Text;

        if (countOfSelectedChars > 0 || paste)
        {
            text = text.Remove(caretIndex, countOfSelectedChars);
            return text.Length + newText.Length;
        }
        else
        {
            var insert = Keyboard.IsKeyToggled(Key.Insert);

            return insert && caretIndex < text.Length ? text.Length : text.Length + newText.Length;
        }
    }
}

这是相关的视图代码:

<TextBox MaxLength="50" TextWrapping="Wrap" MaxWidth="150" Margin="4"
 Text="{Binding Path=FileNameToPublish}" >
     <interactivity:Interaction.Behaviors>
         <v:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9.\-]+$" MaxLength="50" />
     </interactivity:Interaction.Behaviors>
</TextBox>

1
受到这个出色解决方案的启发,我实现了一些改进。请在下面的线程中查看。
亚历克斯·克劳斯

2
你好 我知道这有点晚了,但是我正在尝试实现这一点,但是我一直遇到错误。我猜我缺少一些参考。创建类后,除了默认值以外,是否还有其他可以输入的内容?
发售

1
@Offer是,请确保在xaml窗口顶部包括xmlns:interactivity =“ schemas.microsoft.com/expression/2010/interactivity ”。
WiteCastle 2014年

表达式现在已过时。尽管这种方法是干净的,但它使用的是不再维护的代码。
罗伯特·贝克

1
因此,如果您编辑IsValid函数以返回!ExceedsMaxLength(newText,paste)&& Regex.IsMatch(String.Concat(this.AssociatedObject.Text,newText),RegularExpression); 那么这将评估整个字符串。顺便说一句-喜欢这种行为!
罗加拉2015年

59

这是WilP答案的改进解决方案。我的改进是:

  • 改进了DelBackspace按钮的行为
  • EmptyValue如果不适合使用空字符串,则添加属性
  • 修正了一些小的错别字
/// <summary>
///     Regular expression for Textbox with properties: 
///         <see cref="RegularExpression"/>, 
///         <see cref="MaxLength"/>,
///         <see cref="EmptyValue"/>.
/// </summary>
public class TextBoxInputRegExBehaviour : Behavior<TextBox>
{
    #region DependencyProperties
    public static readonly DependencyProperty RegularExpressionProperty =
        DependencyProperty.Register("RegularExpression", typeof(string), typeof(TextBoxInputRegExBehaviour), new FrameworkPropertyMetadata(".*"));

    public string RegularExpression
    {
        get { return (string)GetValue(RegularExpressionProperty); }
        set { SetValue(RegularExpressionProperty, value); }
    }

    public static readonly DependencyProperty MaxLengthProperty =
        DependencyProperty.Register("MaxLength", typeof(int), typeof(TextBoxInputRegExBehaviour),
                                        new FrameworkPropertyMetadata(int.MinValue));

    public int MaxLength
    {
        get { return (int)GetValue(MaxLengthProperty); }
        set { SetValue(MaxLengthProperty, value); }
    }

    public static readonly DependencyProperty EmptyValueProperty =
        DependencyProperty.Register("EmptyValue", typeof(string), typeof(TextBoxInputRegExBehaviour), null);

    public string EmptyValue
    {
        get { return (string)GetValue(EmptyValueProperty); }
        set { SetValue(EmptyValueProperty, value); }
    }
    #endregion

    /// <summary>
    ///     Attach our behaviour. Add event handlers
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.PreviewTextInput += PreviewTextInputHandler;
        AssociatedObject.PreviewKeyDown += PreviewKeyDownHandler;
        DataObject.AddPastingHandler(AssociatedObject, PastingHandler);
    }

    /// <summary>
    ///     Deattach our behaviour. remove event handlers
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.PreviewTextInput -= PreviewTextInputHandler;
        AssociatedObject.PreviewKeyDown -= PreviewKeyDownHandler;
        DataObject.RemovePastingHandler(AssociatedObject, PastingHandler);
    }

    #region Event handlers [PRIVATE] --------------------------------------

    void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
    {
        string text;
        if (this.AssociatedObject.Text.Length < this.AssociatedObject.CaretIndex)
            text = this.AssociatedObject.Text;
        else
        {
            //  Remaining text after removing selected text.
            string remainingTextAfterRemoveSelection;

            text = TreatSelectedText(out remainingTextAfterRemoveSelection)
                ? remainingTextAfterRemoveSelection.Insert(AssociatedObject.SelectionStart, e.Text)
                : AssociatedObject.Text.Insert(this.AssociatedObject.CaretIndex, e.Text);
        }

        e.Handled = !ValidateText(text);
    }

    /// <summary>
    ///     PreviewKeyDown event handler
    /// </summary>
    void PreviewKeyDownHandler(object sender, KeyEventArgs e)
    {
        if (string.IsNullOrEmpty(this.EmptyValue))
            return;

        string text = null;

        // Handle the Backspace key
        if (e.Key == Key.Back)
        {
            if (!this.TreatSelectedText(out text))
            {
                if (AssociatedObject.SelectionStart > 0)
                    text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart - 1, 1);
            }
        }
        // Handle the Delete key
        else if (e.Key == Key.Delete)
        {
            // If text was selected, delete it
            if (!this.TreatSelectedText(out text) && this.AssociatedObject.Text.Length > AssociatedObject.SelectionStart)
            {
                // Otherwise delete next symbol
                text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, 1);
            }
        }

        if (text == string.Empty)
        {
            this.AssociatedObject.Text = this.EmptyValue;
            if (e.Key == Key.Back)
                AssociatedObject.SelectionStart++;
            e.Handled = true;
        }
    }

    private void PastingHandler(object sender, DataObjectPastingEventArgs e)
    {
        if (e.DataObject.GetDataPresent(DataFormats.Text))
        {
            string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

            if (!ValidateText(text))
                e.CancelCommand();
        }
        else
            e.CancelCommand();
    }
    #endregion Event handlers [PRIVATE] -----------------------------------

    #region Auxiliary methods [PRIVATE] -----------------------------------

    /// <summary>
    ///     Validate certain text by our regular expression and text length conditions
    /// </summary>
    /// <param name="text"> Text for validation </param>
    /// <returns> True - valid, False - invalid </returns>
    private bool ValidateText(string text)
    {
        return (new Regex(this.RegularExpression, RegexOptions.IgnoreCase)).IsMatch(text) && (MaxLength == int.MinValue || text.Length <= MaxLength);
    }

    /// <summary>
    ///     Handle text selection
    /// </summary>
    /// <returns>true if the character was successfully removed; otherwise, false. </returns>
    private bool TreatSelectedText(out string text)
    {
        text = null;
        if (AssociatedObject.SelectionLength <= 0) 
            return false;

        var length = this.AssociatedObject.Text.Length;
        if (AssociatedObject.SelectionStart >= length)
            return true;

        if (AssociatedObject.SelectionStart + AssociatedObject.SelectionLength >= length)
            AssociatedObject.SelectionLength = length - AssociatedObject.SelectionStart;

        text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, AssociatedObject.SelectionLength);
        return true;
    }
    #endregion Auxiliary methods [PRIVATE] --------------------------------
}

用法非常简单:

<i:Interaction.Behaviors>
    <behaviours:TextBoxInputRegExBehaviour RegularExpression="^\d+$" MaxLength="9" EmptyValue="0" />
</i:Interaction.Behaviors>

1
这个解决方案好得多。但是您犯了一个小错误:如果未设置MaxLength条件,则在测试新文本时(this.MaxLength == 0 || text.Length <= this.MaxLength)总会返回条件false。最好这样做是(this.MaxLength == int.MinValue || text.Length <= this.MaxLength)因为您将设置int.MinValue为的默认值MaxLength
ChristophMeißner'17

1
谢谢@Christoph,是的,您是对的。我已经修改了答案。
亚历克斯·克劳斯

@AlexKlaus,在我添加UpdateSourceTrigger=PropertyChanged到绑定之前,它的效果很好。任何想法,当改变如何获得此代码工作UpdateSourceTrigger设置为PropertyChanged?感谢您分享此代码。
初中

32

这是使用MVVM执行此操作的非常简单的方法。

在视图模型中将textBox与一个integer属性绑定,这将像gem一样工作……当在文本框中输入非整数时,它甚至会显示验证。

XAML代码:

<TextBox x:Name="contactNoTxtBox"  Text="{Binding contactNo}" />

查看模型代码:

private long _contactNo;
public long contactNo
{
    get { return _contactNo; }
    set
    {
        if (value == _contactNo)
            return;
        _contactNo = value;
        OnPropertyChanged();
    }
}

但问题包含“我希望接受数字和小数点”。此答案是否接受小数点?
彼得·莫滕森

我尝试将更long改为float,但在立即验证时无法正常运行。我添加UpdateSourceTrigger="PropertyChanged"了绑定,因此它将在键入每个字符时执行验证,并且不再可以键入“。”。除非存在非法字符(必须键入“ 1x.234”,然后删除“ x”),否则在文本框中输入。在这种模式下,它也感觉有些呆滞。这似乎是System.Number.ParseSingle()用来完成工作的,因此它接受各种表示法。

@wolle可能没有投票,因为它没有解释验证的工作原理。
Paul McCarthy

26

添加一个VALIDATION RULE,以便在文本更改时检查数据是否为数字,如果为数字,则允许继续处理,如果不是,则提示用户该字段仅接受数字数据。

在Windows Presentation Foundation中的验证中阅读更多信息


6
这不是SO标准的真正答案。
罗伯特·贝克

这似乎是.net的实现方式。
Telemat

1
正确的答案:验证应在viene模或者模水平。而且,您可以简单地绑定到类似的数字类型,double而这已经为您提供了标准的验证。


20

也可以简单地实现验证规则并将其应用于TextBox:

  <TextBox>
    <TextBox.Text>
      <Binding Path="OnyDigitInput" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <conv:OnlyDigitsValidationRule />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>

遵循以下规则执行(使用与其他答案中建议的相同的Regex):

public class OnlyDigitsValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var validationResult = new ValidationResult(true, null);

        if(value != null)
        {
            if (!string.IsNullOrEmpty(value.ToString()))
            {
                var regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
                var parsingOk = !regex.IsMatch(value.ToString());
                if (!parsingOk)
                {
                    validationResult = new ValidationResult(false, "Illegal Characters, Please Enter Numeric Value");
                }
            }
        }

        return validationResult;
    }
}

如果要输入十进制数字,则当文本以“。”结尾时不要返回“有效”。请访问stackoverflow.com/a/27838893/417939
YantingChen 2016年

14

在这里,我有一个受Ray回答启发的简单解决方案。这应该足以识别任何形式的数字。

如果只需要正数,整数值或精确到最大小数位数的值,也可以轻松修改此解决方案。


Ray的答案所示,您需要首先添加一个PreviewTextInput事件:

<TextBox PreviewTextInput="TextBox_OnPreviewTextInput"/>

然后将以下内容放在代码中:

private void TextBox_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
    var textBox = sender as TextBox;
    // Use SelectionStart property to find the caret position.
    // Insert the previewed text into the existing text in the textbox.
    var fullText = textBox.Text.Insert(textBox.SelectionStart, e.Text);

    double val;
    // If parsing is successful, set Handled to false
    e.Handled = !double.TryParse(fullText, out val);
}

4
我非常喜欢这个答案,简单又有效+
Pulle '18

神和简单,但它允许空间很丑陋
Momo

2
这仍然允许某人将字符串粘贴到文本框中
FCin19年

8

我允许数字键盘数字和退格键:

    private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        int key = (int)e.Key;

        e.Handled = !(key >= 34 && key <= 43 || 
                      key >= 74 && key <= 83 || 
                      key == 2);
    }

8
我建议使用枚举值而不是幻数var keyEnum = (System.Windows.Input.Key) e.Key; e.Handled = !(keyEnum >= System.Windows.Input.Key.D0 && keyEnum <= System.Windows.Input.Key.D9 || keyEnum >= System.Windows.Input.Key.NumPad0 && keyEnum <= System.Windows.Input.Key.NumPad9 || keyEnum == System.Windows.Input.Key.Back);
itsho

7

我将假设:

  1. 您只想为其输入数字的TextBox的Text属性最初设置为某个有效的数字值(例如2.7172)。

  2. 您的文本框是主窗口的子级

  3. 您的主窗口属于Window1类

  4. 您的文本框名称为numericTB

基本思路:

  1. 添加:private string previousText;到您的主窗口类(Window1)

  2. 添加:previousText = numericTB.Text;到您的主窗口构造函数

  3. 为numericTB.TextChanged事件创建一个处理程序,如下所示:

    private void numericTB_TextChanged(object sender, TextChangedEventArgs e)
    {
        double num = 0;
        bool success = double.TryParse(((TextBox)sender).Text, out num);
        if (success & num >= 0)
            previousText = ((TextBox)sender).Text;
        else
            ((TextBox)sender).Text = previousText;
    }

只要有效,就会一直将previousText设置为numericTB.Text,如果用户写了您不喜欢的内容,则将numericTB.Text设置为最后一个有效值。当然,这只是基本思想,只是“防白痴”,而不是“防白痴”。例如,它不能处理用户弄乱空格的情况。因此,这里有一个完整的解决方案,我认为它是“白痴证明”,如果我错了,请告诉我:

  1. 您的Window1.xaml文件的内容:

    <Window x:Class="IdiotProofNumericTextBox.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <TextBox Height="30" Width="100" Name="numericTB" TextChanged="numericTB_TextChanged"/>
        </Grid>
    </Window>
  2. 您的Window.xaml.cs文件的内容:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace IdiotProofNumericTextBox
    {
        public partial class Window1 : Window
        {
            private string previousText;
    
            public Window1()
            {
                InitializeComponent();
                previousText = numericTB.Text;
            }
    
            private void numericTB_TextChanged(object sender, TextChangedEventArgs e)
            {
                if (string.IsNullOrEmpty(((TextBox)sender).Text))
                    previousText = "";
                else
                {
                    double num = 0;
                    bool success = double.TryParse(((TextBox)sender).Text, out num);
                    if (success & num >= 0)
                    {
                        ((TextBox)sender).Text.Trim();
                        previousText = ((TextBox)sender).Text;
                    }
                    else
                    {
                        ((TextBox)sender).Text = previousText;
                        ((TextBox)sender).SelectionStart = ((TextBox)sender).Text.Length;
                    }
                }
            }
        }
    }

就是这样。如果您有多个TextBox,则建议您创建一个从TextBox继承的CustomControl,以便可以将previousText和numericTB_TextChanged包裹在单独的文件中。


哇,太好了!但是,如何在前面允许使用负号?
theNoobGuy 2011年

6

这是唯一需要的代码:

void MyTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = new Regex("[^0-9]+").IsMatch(e.Text);
}

这仅允许将数字输入到文本框中。

要允许小数点或减号,可以将正则表达式更改为[^0-9.-]+


1
除了一个小的nitpick以外,这是一个很好的解决方案:它不会阻止您输入空格,因为这些空格不会触发PreviewTextInput事件。
Tim Pohlmann

退格键也不会触发它。
Winger Sendon '16

6

如果您不想编写很多代码来执行基本功能(我不知道为什么人们会使用长方法),则可以执行以下操作:

  1. 添加名称空间:

    using System.Text.RegularExpressions;
  2. 在XAML中,设置TextChanged属性:

    <TextBox x:Name="txt1" TextChanged="txt1_TextChanged"/>
  3. 在WPF的txt1_TextChanged方法下,添加Regex.Replace

    private void txt1_TextChanged(object sender, TextChangedEventArgs e)
    {
        txt1.Text = Regex.Replace(txt1.Text, "[^0-9]+", "");
    }

2
使用“行为”或“附加属性”要干净得多。在每个视图/每个文本框中都没有代码隐藏的麻烦
Rufo爵士

可能有效,但很丑陋,因为胡萝卜会跳到文本框的前面位置
Momo

6

另一种方法是使用附加行为,我实现了自定义TextBoxHelper类,该类可用于整个项目的文本框。因为我认为为此目的预订每个文本框和每个XAML文件中的事件都是很费时的。

我实现的TextBoxHelper类具有以下功能:

  • 仅过滤和接受数字 DoubleIntUintNatural格式的数字
  • 过滤和只接受奇数号码
  • 处理粘贴事件处理程序以防止将无效文本粘贴到我们的数字文本框中
  • 可以通过预订文本框TextChanged事件来设置默认值,该默认值将用于防止无效数据作为最后的镜头

这是TextBoxHelper类的实现:

public static class TextBoxHelper
{
    #region Enum Declarations

    public enum NumericFormat
    {
        Double,
        Int,
        Uint,
        Natural
    }

    public enum EvenOddConstraint
    {
        All,
        OnlyEven,
        OnlyOdd
    }

    #endregion

    #region Dependency Properties & CLR Wrappers

    public static readonly DependencyProperty OnlyNumericProperty =
        DependencyProperty.RegisterAttached("OnlyNumeric", typeof(NumericFormat?), typeof(TextBoxHelper),
            new PropertyMetadata(null, DependencyPropertiesChanged));
    public static void SetOnlyNumeric(TextBox element, NumericFormat value) =>
        element.SetValue(OnlyNumericProperty, value);
    public static NumericFormat GetOnlyNumeric(TextBox element) =>
        (NumericFormat) element.GetValue(OnlyNumericProperty);


    public static readonly DependencyProperty DefaultValueProperty =
        DependencyProperty.RegisterAttached("DefaultValue", typeof(string), typeof(TextBoxHelper),
            new PropertyMetadata(null, DependencyPropertiesChanged));
    public static void SetDefaultValue(TextBox element, string value) =>
        element.SetValue(DefaultValueProperty, value);
    public static string GetDefaultValue(TextBox element) => (string) element.GetValue(DefaultValueProperty);


    public static readonly DependencyProperty EvenOddConstraintProperty =
        DependencyProperty.RegisterAttached("EvenOddConstraint", typeof(EvenOddConstraint), typeof(TextBoxHelper),
            new PropertyMetadata(EvenOddConstraint.All, DependencyPropertiesChanged));
    public static void SetEvenOddConstraint(TextBox element, EvenOddConstraint value) =>
        element.SetValue(EvenOddConstraintProperty, value);
    public static EvenOddConstraint GetEvenOddConstraint(TextBox element) =>
        (EvenOddConstraint)element.GetValue(EvenOddConstraintProperty);

    #endregion

    #region Dependency Properties Methods

    private static void DependencyPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is TextBox textBox))
            throw new Exception("Attached property must be used with TextBox.");

        switch (e.Property.Name)
        {
            case "OnlyNumeric":
            {
                var castedValue = (NumericFormat?) e.NewValue;

                if (castedValue.HasValue)
                {
                    textBox.PreviewTextInput += TextBox_PreviewTextInput;
                    DataObject.AddPastingHandler(textBox, TextBox_PasteEventHandler);
                }
                else
                {
                    textBox.PreviewTextInput -= TextBox_PreviewTextInput;
                    DataObject.RemovePastingHandler(textBox, TextBox_PasteEventHandler);
                }

                break;
            }

            case "DefaultValue":
            {
                var castedValue = (string) e.NewValue;

                if (castedValue != null)
                {
                    textBox.TextChanged += TextBox_TextChanged;
                }
                else
                {
                    textBox.TextChanged -= TextBox_TextChanged;
                }

                break;
            }
        }
    }

    #endregion

    private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        var textBox = (TextBox)sender;

        string newText;

        if (textBox.SelectionLength == 0)
        {
            newText = textBox.Text.Insert(textBox.SelectionStart, e.Text);
        }
        else
        {
            var textAfterDelete = textBox.Text.Remove(textBox.SelectionStart, textBox.SelectionLength);

            newText = textAfterDelete.Insert(textBox.SelectionStart, e.Text);
        }

        var evenOddConstraint = GetEvenOddConstraint(textBox);

        switch (GetOnlyNumeric(textBox))
        {
            case NumericFormat.Double:
            {
                if (double.TryParse(newText, out double number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Int:
            {
                if (int.TryParse(newText, out int number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Uint:
            {
                if (uint.TryParse(newText, out uint number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Natural:
            {
                if (uint.TryParse(newText, out uint number))
                {
                    if (number == 0)
                        e.Handled = true;
                    else
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;

                                break;
                        }
                    }
                }
                else
                    e.Handled = true;

                break;
            }
        }
    }

    private static void TextBox_PasteEventHandler(object sender, DataObjectPastingEventArgs e)
    {
        var textBox = (TextBox)sender;

        if (e.DataObject.GetDataPresent(typeof(string)))
        {
            var clipboardText = (string) e.DataObject.GetData(typeof(string));

            var newText = textBox.Text.Insert(textBox.SelectionStart, clipboardText);

            var evenOddConstraint = GetEvenOddConstraint(textBox);

            switch (GetOnlyNumeric(textBox))
            {
                case NumericFormat.Double:
                {
                    if (double.TryParse(newText, out double number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();

                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Int:
                {
                    if (int.TryParse(newText, out int number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();


                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Uint:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();


                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Natural:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        if (number == 0)
                            e.CancelCommand();
                        else
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:

                                    if (number % 2 != 0)
                                        e.CancelCommand();

                                    break;

                                case EvenOddConstraint.OnlyOdd:

                                    if (number % 2 == 0)
                                        e.CancelCommand();

                                    break;
                            }
                        }
                    }
                    else
                    {
                        e.CancelCommand();
                    }

                    break;
                }
            }
        }
        else
        {
            e.CancelCommand();
        }
    }

    private static void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        var textBox = (TextBox)sender;

        var defaultValue = GetDefaultValue(textBox);

        var evenOddConstraint = GetEvenOddConstraint(textBox);

        switch (GetOnlyNumeric(textBox))
        {
            case NumericFormat.Double:
            {
                if (double.TryParse(textBox.Text, out double number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Int:
            {
                if (int.TryParse(textBox.Text, out int number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Uint:
            {
                if (uint.TryParse(textBox.Text, out uint number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Natural:
            {
                if (uint.TryParse(textBox.Text, out uint number))
                {
                    if(number == 0)
                        textBox.Text = defaultValue;
                    else
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    textBox.Text = defaultValue;

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    textBox.Text = defaultValue;

                                break;
                        }
                    }
                }
                else
                {
                    textBox.Text = defaultValue;
                }

                break;
            }
        }
    }
}

这里是一些易于使用的示例:

<TextBox viewHelpers:TextBoxHelper.OnlyNumeric="Double"
         viewHelpers:TextBoxHelper.DefaultValue="1"/>

要么

<TextBox viewHelpers:TextBoxHelper.OnlyNumeric="Natural"
         viewHelpers:TextBoxHelper.DefaultValue="3"
         viewHelpers:TextBoxHelper.EvenOddConstraint="OnlyOdd"/>

请注意,我的TextBoxHelper位于viewHelpers xmlns别名中。

我希望这种实现方式可以减轻其他人的工作:)


1
在DataTemplate内部使用文本框时,这很棒,谢谢!
NucS

@NucS亲爱的NucS非常欢迎您
Amir Mahdi Nassiri

3
很好的答案,但我发现您的方法很难阅读。可能您应该将它们分解成较小的部分。请参阅哪种方法适合您?
安东尼

感谢您的建设性反馈@Anthony
Amir Mahdi Nassiri

4
e.Handled = (int)e.Key >= 43 || (int)e.Key <= 34;

在文本框的预览keydown事件中。


3
但是不允许使用退格键。
sventevit 2012年

2
退格键为2,制表符为3
Daniel

6
-1是因为像其他评论者所指出的那样,根据我的经验,这种巧妙的技巧最终会把您咬死。
DonkeyMaster

左箭头是23,右箭头为25
阿伦


4

对于那些希望仅使用整数和十进制来解决此类问题的快速且非常简单的实现者,请在您的XAML文件中添加一个PreviewTextInput属性TextBox,然后在您的xaml.cs文件中使用:

private void Text_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !char.IsDigit(e.Text.Last()) && !e.Text.Last() == '.';
}

每次都检查整个字符串是多余的,除非像其他人提到的那样,您正在用科学记数法做某事(尽管如果要添加某些字符,例如“ e”,则简单的正则表达式会添加符号/字符非常简单,并在其他答案中进行了说明)。但是对于简单的浮点值,此解决方案就足够了。

写成带有lambda表达式的单线:

private void Text_PreviewTextInput(object sender, TextCompositionEventArgs e) => e.Handled = !char.IsDigit(e.Text.Last() && !e.Text.Last() == '.');

3

我们可以对文本框更改事件进行验证。以下实现防止数字和小数点以外的按键输入。

private void textBoxNumeric_TextChanged(object sender, TextChangedEventArgs e) 
{         
      TextBox textBox = sender as TextBox;         
      Int32 selectionStart = textBox.SelectionStart;         
      Int32 selectionLength = textBox.SelectionLength;         
      String newText = String.Empty;         
      int count = 0;         
      foreach (Char c in textBox.Text.ToCharArray())         
      {             
         if (Char.IsDigit(c) || Char.IsControl(c) || (c == '.' && count == 0))             
         {                 
            newText += c;                 
            if (c == '.')                     
              count += 1;             
         }         
     }         
     textBox.Text = newText;         
     textBox.SelectionStart = selectionStart <= textBox.Text.Length ? selectionStart :        textBox.Text.Length;     
} 

它对我不起作用:)
david2020

3

这个怎么样?对我来说效果很好。希望我不会错过任何优秀的案例...

MyTextBox.PreviewTextInput += (sender, args) =>
{
    if (!int.TryParse(args.Text, out _))
    {
        args.Handled = true;
    }
};

DataObject.AddPastingHandler(MyTextBox, (sender, args) =>
{
    var isUnicodeText = args.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
    if (!isUnicodeText)
    {
        args.CancelCommand();
    }

    var data = args.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
    if (!int.TryParse(data, out _))
    {
        args.CancelCommand();
    }
});

2

在Windows窗体中,这很容易。您可以为KeyPress添加一个事件,然后一切都会轻松进行。但是,在WPF中不存在该事件。但是,有一种更简单的方法。

WPF TextBox具有TextChanged事件,该事件对于所有事件都是常规的。它包括粘贴,键入以及您可以想到的所有内容。

因此,您可以执行以下操作:

XAML:

<TextBox name="txtBox1" ... TextChanged="TextBox_TextChanged"/>

代码如下:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e) {
    string s = Regex.Replace(((TextBox)sender).Text, @"[^\d.]", "");
    ((TextBox)sender).Text = s;
}

这也可以接受.,如果您不想要它,只需将其从regex语句be中删除@[^\d]

注意:由于此事件使用sender对象的Text ,因此可以在许多TextBox上使用。您只需编写一次事件,即可将其用于多个TextBox。


2

现在,我知道这个问题的答案已经被接受,但是就我个人而言,我感到有点困惑,我认为应该比这更容易。因此,我将尝试说明如何使它尽可能发挥最大作用:

Windows Forms中,有一个名为的事件KeyPress非常适合此类任务。但这在WPF中不存在,因此,我们将使用该PreviewTextInput事件。另外,对于验证,我相信可以使用a foreach来遍历textbox.Textand检查是否匹配 ;)条件,但是说实话,这就是正则表达式的用途。

在深入探讨圣典之前,还有另一件事。对于要触发的事件,可以做两件事:

  1. 使用XAML告诉程序要调用哪个函数: <PreviewTextInput="textBox_PreviewTextInput/>
  2. 做到这一点的Loaded形式(该文本框的地方)的事件: textBox.PreviewTextInput += onlyNumeric;

我认为第二种方法更好,因为在这种情况下,通常需要将相同的条件(regex)应用于多个条件,TextBox并且您不想重复自己!

最后,这是您的处理方式:

private void onlyNumeric(object sender, TextCompositionEventArgs e)
{
    string onlyNumeric = @"^([0-9]+(.[0-9]+)?)$";
    Regex regex = new Regex(onlyNumeric);
    e.Handled = !regex.IsMatch(e.Text);
}

2

这是我的版本。它基于一个基ValidatingTextBox类,如果它不是“有效”的,它只会撤消已完成的操作。它支持粘贴,剪切,删除,退格,+,-等。

对于32位整数,有一个Int32TextBox类仅与int比较。我还添加了浮点验证类。

public class ValidatingTextBox : TextBox
{
    private bool _inEvents;
    private string _textBefore;
    private int _selectionStart;
    private int _selectionLength;

    public event EventHandler<ValidateTextEventArgs> ValidateText;

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        if (_inEvents)
            return;

        _selectionStart = SelectionStart;
        _selectionLength = SelectionLength;
        _textBefore = Text;
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        if (_inEvents)
            return;

        _inEvents = true;
        var ev = new ValidateTextEventArgs(Text);
        OnValidateText(this, ev);
        if (ev.Cancel)
        {
            Text = _textBefore;
            SelectionStart = _selectionStart;
            SelectionLength = _selectionLength;
        }
        _inEvents = false;
    }

    protected virtual void OnValidateText(object sender, ValidateTextEventArgs e) => ValidateText?.Invoke(this, e);
}

public class ValidateTextEventArgs : CancelEventArgs
{
    public ValidateTextEventArgs(string text) => Text = text;

    public string Text { get; }
}

public class Int32TextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !int.TryParse(e.Text, out var value);
}

public class Int64TextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !long.TryParse(e.Text, out var value);
}

public class DoubleTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !double.TryParse(e.Text, out var value);
}

public class SingleTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !float.TryParse(e.Text, out var value);
}

public class DecimalTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !decimal.TryParse(e.Text, out var value);
}

注意1:使用WPF绑定时,必须确保使用适合绑定属性类型的类,否则可能会导致奇怪的结果。

注意2:将浮点类与WPF绑定一起使用时,请确保绑定使用当前区域性以匹配我使用的TryParse方法。



1

采用:

Private Sub DetailTextBox_PreviewTextInput( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Input.TextCompositionEventArgs) _
  Handles DetailTextBox.PreviewTextInput

    If _IsANumber Then
        If Not Char.IsNumber(e.Text) Then
            e.Handled = True
        End If
    End If
End Sub

一个解释将是有条理的。
彼得·莫滕森

1

我正在使用一个未绑定的盒子来处理我正在处理的一个简单项目,因此我无法使用标准的绑定方法。因此,我通过扩展现有的TextBox控件创建了一个简单的技巧,其他人可能会很方便:

namespace MyApplication.InterfaceSupport
{
    public class NumericTextBox : TextBox
    {


        public NumericTextBox() : base()
        {
            TextChanged += OnTextChanged;
        }


        public void OnTextChanged(object sender, TextChangedEventArgs changed)
        {
            if (!String.IsNullOrWhiteSpace(Text))
            {
                try
                {
                    int value = Convert.ToInt32(Text);
                }
                catch (Exception e)
                {
                    MessageBox.Show(String.Format("{0} only accepts numeric input.", Name));
                    Text = "";
                }
            }
        }


        public int? Value
        {
            set
            {
                if (value != null)
                {
                    this.Text = value.ToString();
                }
                else 
                    Text = "";
            }
            get
            {
                try
                {
                    return Convert.ToInt32(this.Text);
                }
                catch (Exception ef)
                {
                    // Not numeric.
                }
                return null;
            }
        }
    }
}

显然,对于浮动类型,您可能希望将其解析为浮点型,依此类推。相同的原则适用。

然后,在XAML文件中,您需要包含相关的名称空间:

<UserControl x:Class="MyApplication.UserControls.UnParameterisedControl"
             [ Snip ]
             xmlns:interfaceSupport="clr-namespace:MyApplication.InterfaceSupport"
             >

之后,您可以将其用作常规控件:

<interfaceSupport:NumericTextBox Height="23" HorizontalAlignment="Left" Margin="168,51,0,0" x:Name="NumericBox" VerticalAlignment="Top" Width="120" >

1

在这里使用了一些解决方案一段时间后,我开发了自己的解决方案,该解决方案非常适合我的MVVM设置。请注意,在允许用户输入错误字符的意义上,它不像其他一些字符那样动态,但是它阻止了用户按下按钮并因此无法执行任何操作。这与我的主题(无法执行操作时将按钮显示为灰色)配合得很好。

我有一个TextBox用户必须输入要打印的许多文档页面的信息:

<TextBox Text="{Binding NumberPagesToPrint, UpdateSourceTrigger=PropertyChanged}"/>

...具有此绑定属性:

private string _numberPagesToPrint;
public string NumberPagesToPrint
{
    get { return _numberPagesToPrint; }
    set
    {
        if (_numberPagesToPrint == value)
        {
            return;
        }

        _numberPagesToPrint = value;
        OnPropertyChanged("NumberPagesToPrint");
    }
}

我也有一个按钮:

<Button Template="{DynamicResource CustomButton_Flat}" Content="Set"
        Command="{Binding SetNumberPagesCommand}"/>

...通过以下命令绑定:

private RelayCommand _setNumberPagesCommand;
public ICommand SetNumberPagesCommand
{
    get
    {
        if (_setNumberPagesCommand == null)
        {
            int num;
            _setNumberPagesCommand = new RelayCommand(param => SetNumberOfPages(),
                () => Int32.TryParse(NumberPagesToPrint, out num));
        }

        return _setNumberPagesCommand;
    }
}

然后是的方法SetNumberOfPages(),但是对于本主题而言并不重要。在我的情况下,它可以很好地工作,因为我不必在View的代码隐藏文件中添加任何代码,并且可以使用该Command属性控制行为。



1

在WPF应用程序中,可以通过处理TextChanged事件来处理此问题:

void arsDigitTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
    Regex regex = new Regex("[^0-9]+");
    bool handle = regex.IsMatch(this.Text);
    if (handle)
    {
        StringBuilder dd = new StringBuilder();
        int i = -1;
        int cursor = -1;
        foreach (char item in this.Text)
        {
            i++;
            if (char.IsDigit(item))
                dd.Append(item);
            else if(cursor == -1)
                cursor = i;
        }
        this.Text = dd.ToString();

        if (i == -1)
            this.SelectionStart = this.Text.Length;
        else
            this.SelectionStart = cursor;
    }
}

1

对于希望其文本字段仅接受无符号数字(例如套接字端口等)的开发人员:

WPF

<TextBox PreviewTextInput="Port_PreviewTextInput" MaxLines="1"/>

C#

private void Port_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !int.TryParse(e.Text, out int x);
}

2
请注意,如果您确实想将此方法与套接字端口字段一起使用,请参见:您需要检查整数是否小于或等于65535。如果更大,则它不是有效端口。另外,将设置TextBox.MaxLength5以编程方式或XAML帮助。
Beyondo

0

这就是我用来获取可以接受数字和小数点的WPF文本框的方式:

class numericTextBox : TextBox
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        bool b = false;
        switch (e.Key)
        {
            case Key.Back: b = true; break;
            case Key.D0: b = true; break;
            case Key.D1: b = true; break;
            case Key.D2: b = true; break;
            case Key.D3: b = true; break;
            case Key.D4: b = true; break;
            case Key.D5: b = true; break;
            case Key.D6: b = true; break;
            case Key.D7: b = true; break;
            case Key.D8: b = true; break;
            case Key.D9: b = true; break;
            case Key.OemPeriod: b = true; break;
        }
        if (b == false)
        {
            e.Handled = true;
        }
        base.OnKeyDown(e);
    }
}

将代码放在新的类文件中,添加

using System.Windows.Controls;
using System.Windows.Input;

在文件顶部,然后构建解决方案。然后,numericTextBox控件将出现在工具箱的顶部。


1
请参阅使用NumberValidationTextBox和正则表达式的更简单的解决方案。这是荒唐的。
Scott Shaw-Smith

@ ScottShaw-Smith也许公认的解决方案是更少的代码,但是并没有比这快。总有一些项目需要大量的处理能力,而不是使用正则表达式。
Beyondo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.