如何在用户输入字符时测试 UITextField 的字符输入并防止无效字符

发布于 2025-01-06 12:51:07 字数 153 浏览 2 评论 0原文

首先,我为 UITextField 设置键盘以使用小数样式的数字。因此用户只能输入数字和一个小数。

我想要做的是在用户输入时测试输入并防止输入多个小数并将数字的小数部分限制为两位。我不想对数字进行四舍五入,甚至不想将输入视为数字。我只是想阻止用户在小数点右侧输入超过两位数字。

First, I setup up the keyboard for the UITextField to use the number with decimal style. So the user can only enter numbers and a single decimal.

What I want to do is test the input as the user enters it and prevent multiple decimals from being entered and limit the decimal portion of the number to two places. I do not want to round off the number nor even treat the input as a number. I simply want to prevent the user from entering more then two digits to the right of the decimal place.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

‘画卷フ 2025-01-13 12:51:07

最终结果证明该解决方案相当微不足道。不幸的是,与此问题相关的许多问题和答案都是关于验证或格式化数值,而不是控制用户可以输入的内容。

shouldChangeCharactersInRange 委托方法的以下实现是我的解决方案。与往常一样,正则表达式在这种情况下很有效。 RegExLib.com 是有用的 RegEx 示例或解决方案的绝佳来源。我不是正则表达式专家,总是在将它们组合在一起时遇到一些困难,因此欢迎提出改进它的建议。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField == self.quantityTextField)
    {
        NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

        NSString *expression = @"^([0-9]+)?(\\.([0-9]{1,2})?)?$";

        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression 
                                                                               options:NSRegularExpressionCaseInsensitive 
                                                                                 error:nil];
        NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString
                                                            options:0
                                                              range:NSMakeRange(0, [newString length])];        
        if (numberOfMatches == 0)
            return NO;        
    }

    return YES;
}

上面的代码允许用户输入这些类型的值:1、1.1、1.11、.1、.11。请注意,此实现不会替换文本字段的字符串,否则会导致递归。如果“newString”与正则表达式不匹配,此解决方案将简单地拒绝用户输入的下一个字符。

The solution ultimately turned out to be fairly trivial. Unfortunately a lot of the questions and answers related to this question are about validating or formatting numeric values, not controlling what a user could input.

The following implementation of the shouldChangeCharactersInRange delegate method is my solution. As always, regular expressions rock in this situation. RegExLib.com is an excellent source for useful RegEx samples or solutions. I'm not a RegEx guru and always struggle a bit putting them together so any suggestions to improve it are welcome.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField == self.quantityTextField)
    {
        NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

        NSString *expression = @"^([0-9]+)?(\\.([0-9]{1,2})?)?$";

        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression 
                                                                               options:NSRegularExpressionCaseInsensitive 
                                                                                 error:nil];
        NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString
                                                            options:0
                                                              range:NSMakeRange(0, [newString length])];        
        if (numberOfMatches == 0)
            return NO;        
    }

    return YES;
}

The above code allows the user to input these kinds of values: 1, 1.1, 1.11, .1, .11. Notice that this implementation does not replace the text field's string, which would causes a recursion. This solution simply rejects the next character the user inputs if the 'newString' does not match the regex.

金橙橙 2025-01-13 12:51:07

好的!如果有人需要它使用非美国货币:欧元或其他用逗号而不是点分隔小数的货币,请使用这个:

NSString *expression = @"^([0-9]+)?([\\,\\.]([0-9]{1,2})?)?$";

唯一的区别是它允许逗号或点。 ([\,\.] - . 或 ,) 唯一的技巧是在使用获取的数字时需要用点替换逗号,因为计算机使用点来分隔分数,而不是逗号。

Good! If someone need it working with non-US currencies: euro or other ones with fraction separated by comma instead of dot use this one:

NSString *expression = @"^([0-9]+)?([\\,\\.]([0-9]{1,2})?)?$";

The only difference is that it allows comma or dot. ([\,\.] - either . or ,) Only trick is that you need to replace comma with dot when using your acquired number, because computer uses dot to separate fraction, not the comma.

辞慾 2025-01-13 12:51:07

在 iOS 中处理此问题的标准方法是将 UITextFieldDelegate 附加到 UITextField,并实现 textField:shouldChangeCharactersInRange:replacementString: 方法。在此方法中,您可以验证字符串是否具有适合您目的的正确“形状”(一个点、点后不超过两位数字等),并在输入不符合预期格式时提供不同的字符串。

The standard way of dealing with this issue in iOS is attaching a UITextFieldDelegate to your UITextField, and implement textField:shouldChangeCharactersInRange:replacementString: method. Inside this method you can validate the string to be of the correct "shape" for your purposes (one dot, no more than two digits after the dot, etc.) and supply a different string if the input does not follow the expected format.

冷弦 2025-01-13 12:51:07

经过大量实验并查看其他解决方案(似乎过于复杂和繁琐)后,我想出了以下解决方案,它可以防止用户输入除有效货币金额之外的任何内容。基本上,让 NSNumberFormatter 实例(在 viewController 中的其他位置创建)完成这项艰苦的工作:

  • 1)将文本转换为数字(如果为 nil,则存在无效字符,因此返回 NO)
  • 2)然后将数字转换为货币
  • 3 )然后将货币字符串转换回数字,如果与原始字符串不同(意味着输入了太多小数),则返回 NO
  • 4)然后创建一个 NSDecimalNumber,这就是我想要的。当然,对你来说可能会有所不同。
    到目前为止对我有用 - 希望这对某人有帮助。

首先,我将键盘设置为 UIKeyboardTypeDecimalPad。然后我使用了以下代码

  -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

NSString *textString = [textField.text stringByReplacingCharactersInRange:range withString:string];

[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *amountNumber = [numberFormatter numberFromString:textString];

if ([textString length] > 0) {
    if (!amountNumber) {
        return NO;
    }
} else {
    amountNumber = @0;
}


[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *amountStringer = [numberFormatter stringFromNumber:amountNumber];
NSNumber *amountAgain = [numberFormatter numberFromString:amountStringer];

//
//make sure that the number obtained again is the same....prevents too many decimals....
if (![amountNumber isEqualToNumber:amountAgain]) {
    return NO;
}

[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
amountShow.text = amountStringer;

self.amount = [NSDecimalNumber decimalNumberWithDecimal:[amountAgain decimalValue]];
NSLog(@"decimal Amount is %@", self.amount);

return YES;

}

After much experimentation and looking at other's solutions (which seem to be overly complex and fiddly) I came up with the following, which prevents the user from entering anything but a valid currency amount. Basically, let an instance of NSNumberFormatter (created elsewhere in the viewController) do the hard work:

  • 1) convert the text to a number (if nil, then there are invalid characters, so return NO)
  • 2) then convert the number to currency
  • 3) then convert the currency string back to number and, if different to the original (means too many decimals entered), return NO
  • 4) then make an NSDecimalNumber, which is what I wanted. May be different for you, of course.
    Works for me so far - hope that this helps someone.

Firstly, I set the keyboard to UIKeyboardTypeDecimalPad. Then I used the following code

  -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

NSString *textString = [textField.text stringByReplacingCharactersInRange:range withString:string];

[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *amountNumber = [numberFormatter numberFromString:textString];

if ([textString length] > 0) {
    if (!amountNumber) {
        return NO;
    }
} else {
    amountNumber = @0;
}


[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *amountStringer = [numberFormatter stringFromNumber:amountNumber];
NSNumber *amountAgain = [numberFormatter numberFromString:amountStringer];

//
//make sure that the number obtained again is the same....prevents too many decimals....
if (![amountNumber isEqualToNumber:amountAgain]) {
    return NO;
}

[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
amountShow.text = amountStringer;

self.amount = [NSDecimalNumber decimalNumberWithDecimal:[amountAgain decimalValue]];
NSLog(@"decimal Amount is %@", self.amount);

return YES;

}

尘曦 2025-01-13 12:51:07

对于 Swift 4 问题的主要答案是

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard textField == quantityTextField, let textFieldString = textField.text as NSString? else {
        return true
    }

    let newString = textFieldString.replacingCharacters(in: range, with: string)
    let expression = "^([0-9]+)?(\\.([0-9]{1,2})?)?$"

    let regex = try? NSRegularExpression(pattern: expression, options: .caseInsensitive)
    let numberOfMathces = regex?.numberOfMatches(in: newString, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, newString.characters.count))

    if numberOfMathces == 0 {
        return false
    }

    return true
}

For Swift 4 main answer of question is

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard textField == quantityTextField, let textFieldString = textField.text as NSString? else {
        return true
    }

    let newString = textFieldString.replacingCharacters(in: range, with: string)
    let expression = "^([0-9]+)?(\\.([0-9]{1,2})?)?$"

    let regex = try? NSRegularExpression(pattern: expression, options: .caseInsensitive)
    let numberOfMathces = regex?.numberOfMatches(in: newString, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, newString.characters.count))

    if numberOfMathces == 0 {
        return false
    }

    return true
}
枫以 2025-01-13 12:51:07

您可以将 uitexfield 的字符串传递给下面的方法,它将返回 yes/no..因此您可以显示错误

- (BOOL) validatePhone: (NSString *) aMobile {
    NSString *phoneRegex = @"^+(?:[0-9] ?){6,14}[0-9]$"; 
    NSPredicate *phoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", phoneRegex];
    if (aMobile.length>0) {
        NSString *mobileTextString = [[mobileText.text componentsSeparatedByCharactersInSet:
                                       [[NSCharacterSet decimalDigitCharacterSet] invertedSet]] 
                                      componentsJoinedByString:@""];
        NSString *firstNumber = [aMobile substringToIndex:1];
       if (mobileTextString.length!=10){

            return NO;
        }

    }
        return [phoneTest evaluateWithObject:aMobile];
}

You can pass the string of uitexfield to below method, it will return yes/no..accordingly you can show error

- (BOOL) validatePhone: (NSString *) aMobile {
    NSString *phoneRegex = @"^+(?:[0-9] ?){6,14}[0-9]$"; 
    NSPredicate *phoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", phoneRegex];
    if (aMobile.length>0) {
        NSString *mobileTextString = [[mobileText.text componentsSeparatedByCharactersInSet:
                                       [[NSCharacterSet decimalDigitCharacterSet] invertedSet]] 
                                      componentsJoinedByString:@""];
        NSString *firstNumber = [aMobile substringToIndex:1];
       if (mobileTextString.length!=10){

            return NO;
        }

    }
        return [phoneTest evaluateWithObject:aMobile];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文