如何在用户input字符并防止无效字符时testing字符input到UITextField

首先,我为UITextField设置键盘以使用带有小数点的数字。 所以用户只能input数字和一个小数。

我想要做的是在用户input时testinginput,防止input多个小数,并将数字的小数部分限制在两个地方。 我不想把这个数字四舍五入,甚至不把input作为一个数字。 我只是想阻止用户input小数点右侧的两位数字。

解决scheme最终certificate是相当微不足道的。 不幸的是,与这个问题有关的许多问题和答案都是关于validation或格式化数值,而不是控制用户可以input的内容。

下面的shouldChangeCharactersInRange委托方法的实现是我的解决scheme。 一如往常,正则expression式在这种情况下摇摆不定 RegExLib.com是有用的RegEx示例或解决scheme的绝佳来源。 我不是一个RegEx的大师,总是把他们拼在一起,所以任何改善它的build议,都是值得欢迎的。

- (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; } 

上面的代码允许用户input这些types的值:1,1.1,1.11,1 .11。 请注意,这个实现不会replace文本字段的string,这会导致recursion。 如果'newString'与正则expression式不匹配,这个解决scheme只会拒绝用户input的下一个字符。

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

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

唯一的区别是它允许逗号或点。 ([\,\。] – 或者,),唯一的窍门是你需要用点来代替逗号,因为计算机使用点来分隔分数,而不是逗号。

在iOS中处理这个问题的标准方法是将UITextFieldDelegate附加到您的UITextField ,并实现textField:shouldChangeCharactersInRange:replacementString:方法。 在这个方法里面,你可以validationstring是正确的“形状”(为一个点,在点之后不超过两个数字),并且如果input不符合预期的格式,则提供一个不同的string。

经过大量的实验,看着其他的解决scheme(这似乎是过于复杂和繁琐),我想出了以下,防止用户input任何东西,但有效的货币金额。 基本上,让一个NSNumberFormatter(在viewController的其他地方创build)的一个实例做的努力:

  • 1)将文本转换为数字(如果nil,则有无效字符,所以返回NO)
  • 2)然后将数字转换为货币
  • 3)然后将货币string转换回数字,如果与原始数据不同(意味着input了太多小数),则返回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; 

}

对于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 } 

您可以将uitexfieldstring传递给下面的方法,它将返回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]; }