Как проверить ввод символов в UITextField, когда пользователь вводит символы и предотвращает недопустимые символы
Сначала я настраиваю клавиатуру для UITextField, чтобы использовать число с десятичным стилем. Таким образом, пользователь может вводить только числа и одну десятичную цифру.
То, что я хочу сделать, это проверить ввод, когда пользователь вводит его, и предотвратить ввод нескольких десятичных знаков и ограничить десятичную часть номера до двух мест. Я не хочу округлять число и даже рассматривать ввод как число. Я просто хочу, чтобы пользователь не вводил более двух цифр справа от десятичной точки.
Ответы
Ответ 1
Решение в конечном итоге оказалось довольно тривиальным. К сожалению, многие вопросы и ответы, связанные с этим вопросом, касаются проверки или форматирования числовых значений, а не контроля того, что пользователь мог бы ввести.
Следующей реализацией метода делегата shouldChangeCharactersInRange является мое решение. Как всегда, в этой ситуации возникают обычные выражения. RegExLib.com - отличный источник полезных примеров или решений RegEx. Я не гуру 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" не соответствует регулярному выражению.
Ответ 2
Хорошо! Если кому-то это нужно, работая с валютами, отличными от США: евро или другие с дробью, разделенной запятой, а не точкой, используйте эту:
NSString *expression = @"^([0-9]+)?([\\,\\.]([0-9]{1,2})?)?$";
Единственное отличие состоит в том, что он позволяет запятую или точку. ([\, \.] - либо. или,) Только трюк заключается в том, что вам нужно заменить запятую точкой при использовании вашего приобретенного номера, потому что компьютер использует точку для разделения фракции, а не запятую.
Ответ 3
Стандартный способ решения этой проблемы в iOS - это привязать UITextFieldDelegate
к вашему UITextField
и реализовать метод textField:shouldChangeCharactersInRange:replacementString:
. Внутри этого метода вы можете проверить правильность строки для вашей цели (одна точка, не более двух цифр после точки и т.д.) И указать другую строку, если вход не соответствует ожидаемому формату.
Ответ 4
После долгих экспериментов и поиска других решений (которые кажутся чересчур сложными и неудобными) я придумал следующее, что не позволяет пользователю вводить что-либо, кроме действительной суммы валюты. В принципе, пусть экземпляр 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;
}
Ответ 5
Для 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
}
Ответ 6
Вы можете передать строку uitexfield ниже метода, она вернет yes/no..accordingly вы можете показать ошибку
- (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];
}