Verifique se uma input para UITextField é apenas numérica

Como eu valido a input de string para um UITextField ? Eu quero verificar se a string é numérica, incluindo pontos decimais.

Eu uso este código no meu aplicativo Mac, o mesmo ou similar deve funcionar com o iPhone. É baseado nas expressões regulares RegexKitLite e torna o texto vermelho quando é inválido.

 static bool TextIsValidValue( NSString* newText, double &value ) { bool result = false; if ( [newText isMatchedByRegex:@"^(?:|0|[1-9]\\d*)(?:\\.\\d*)?$"] ) { result = true; value = [newText doubleValue]; } return result; } - (IBAction) doTextChanged:(id)sender; { double value; if ( TextIsValidValue( [i_pause stringValue], value ) ) { [i_pause setTextColor:[NSColor blackColor]]; // do something with the value } else { [i_pause setTextColor:[NSColor redColor]]; } } 

Você pode fazer isso em poucas linhas como esta:

 BOOL valid; NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet]; NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:myInputField.text]; valid = [alphaNums isSupersetOfSet:inStringSet]; if (!valid) // Not numeric 

– isto é para validação de input é apenas caracteres numéricos. Veja a documentação do NSCharacterSet para as outras opções. Você pode usar characterSetWithCharactersInString para especificar qualquer conjunto de caracteres de input válidos.

Existem algumas maneiras de fazer isso:

  1. Use o método numberFromString: do NSNumberFormatter. Isso retornará um NSNumber se puder analisar a string corretamente, ou nil se não puder.
  2. Use o NSScanner
  3. Retira qualquer caractere não numérico e verifica se a string ainda corresponde
  4. Use uma expressão regular

IMO, usando algo como -[NSString doubleValue] não seria a melhor opção, porque tanto @"0.0" como @"abc" terão um doubleValue de 0. Os methods de valor * retornam todos 0 se não puderem converter a string corretamente, então seria difícil distinguir entre uma string legítima de @"0" e uma string inválida. Algo como a function strtol do C teria o mesmo problema.

Acho que usar o NSNumberFormatter seria a melhor opção, já que leva em conta o local (ou seja, o número @"1,23" na Europa, contra @"1.23" nos EUA).

Se você quiser que um usuário só tenha permissão para digitar numerais, você pode fazer com que seu ViewController implemente parte do UITextFieldDelegate e defina este método:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSString *resultingString = [textField.text stringByReplacingCharactersInRange: range withString: string]; // The user deleting all input is perfectly acceptable. if ([resultingString length] == 0) { return true; } NSInteger holder; NSScanner *scan = [NSScanner scannerWithString: resultingString]; return [scan scanInteger: &holder] && [scan isAtEnd]; } 

Provavelmente existem maneiras mais eficientes, mas acho isso uma maneira bastante conveniente . E o método deve ser facilmente adaptável para validar duplas ou qualquer outra coisa: basta usar scanDouble: ou similar.

 #pragma mark - UItextfield Delegate - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if ([string isEqualToString:@"("]||[string isEqualToString:@")"]) { return TRUE; } NSLog(@"Range ==%d ,%d",range.length,range.location); //NSRange *CURRANGE = [NSString rangeOfString:string]; if (range.location == 0 && range.length == 0) { if ([string isEqualToString:@"+"]) { return TRUE; } } return [self isNumeric:string]; } -(BOOL)isNumeric:(NSString*)inputString{ BOOL isValid = NO; NSCharacterSet *alphaNumbersSet = [NSCharacterSet decimalDigitCharacterSet]; NSCharacterSet *stringSet = [NSCharacterSet characterSetWithCharactersInString:inputString]; isValid = [alphaNumbersSet isSupersetOfSet:stringSet]; return isValid; } 

Aqui estão alguns one-liners que combinam a resposta de Peter Lewis acima ( Verifique se uma input para UITextField é apenas numérica ) com NSPredicates

  #define REGEX_FOR_NUMBERS @"^([+-]?)(?:|0|[1-9]\\d*)(?:\\.\\d*)?$" #define REGEX_FOR_INTEGERS @"^([+-]?)(?:|0|[1-9]\\d*)?$" #define IS_A_NUMBER(string) [[NSPredicate predicateWithFormat:@"SELF MATCHES %@", REGEX_FOR_NUMBERS] evaluateWithObject:string] #define IS_AN_INTEGER(string) [[NSPredicate predicateWithFormat:@"SELF MATCHES %@", REGEX_FOR_INTEGERS] evaluateWithObject:string] 

Para teste inteiro, será:

 - (BOOL) isIntegerNumber: (NSString*)input { return [input integerValue] != 0 || [input isEqualToString:@"0"]; } 

Você pode usar o doubleValue da sua string como

 NSString *string=@"1.22"; double a=[string doubleValue]; 

Eu acho que isso retornará um valor igual a 0.0 se a string for inválida (ele pode lançar uma exceção, caso em que você pode pegá-la, os documentos dizem 0.0 tho). mais informações aqui

Oi tinha exatamente o mesmo problema e não vejo a resposta que usei postada, então aqui está.

Eu criei e conectei meu campo de texto via IB. Quando o conectei ao meu código via Control + Drag, escolhi Action e selecionei o evento Editing Changed. Isso aciona o método em cada input de caractere. Você pode usar um evento diferente para se adequar.

Depois, usei este código simples para replace o texto. Observe que eu criei meu próprio conjunto de caracteres para include o caractere decimal / período e os números. Basicamente, separa a string nos caracteres inválidos e depois os reúne com uma string vazia.

 - (IBAction)myTextFieldEditingChangedMethod:(UITextField *)sender { NSCharacterSet *validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@".0123456789"]; NSCharacterSet *invalidCharacterSet = validCharacterSet.invertedSet; sender.text = [[sender.text componentsSeparatedByCharactersInSet:invalidCharacterSet] componentsJoinedByString:@""]; } 

Créditos: remova todos os números da NSString

Tarde para o jogo, mas aqui uma pequena categoria útil que uso para contas decimais e o símbolo local usado para isso. link para sua essência aqui

 @interface NSString (Extension) - (BOOL) isAnEmail; - (BOOL) isNumeric; @end @implementation NSString (Extension) /** * Determines if the current string is a valid email address. * * @return BOOL - True if the string is a valid email address. */ - (BOOL) isAnEmail { NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex]; return [emailTest evaluateWithObject:self]; } /** * Determines if the current NSString is numeric or not. It also accounts for the localised (Germany for example use "," instead of ".") decimal point and includes these as a valid number. * * @return BOOL - True if the string is numeric. */ - (BOOL) isNumeric { NSString *localDecimalSymbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]; NSMutableCharacterSet *decimalCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:localDecimalSymbol]; [decimalCharacterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]]; NSCharacterSet* nonNumbers = [decimalCharacterSet invertedSet]; NSRange r = [self rangeOfCharacterFromSet: nonNumbers]; if (r.location == NSNotFound) { // check to see how many times the decimal symbol appears in the string. It should only appear once for the number to be numeric. int numberOfOccurances = [[self componentsSeparatedByString:localDecimalSymbol] count]-1; return (numberOfOccurances > 1) ? NO : YES; } else return NO; } @end 

IMO a melhor maneira de realizar seu objective é exibir um teclado numérico em vez do teclado normal. Isso restringe quais chaves estão disponíveis para o usuário. Isso alivia a necessidade de validação e, mais importante, evita que o usuário cometa um erro. O teclado numérico também é muito mais agradável para inserir números porque as teclas são substancialmente maiores.

No construtor de interface, selecione o UITextField, vá para o Inspetor de Atributos e altere o “Tipo de Teclado” para “Decimal Pad”.

insira a descrição da imagem aqui

Isso fará com que o teclado fique assim:

insira a descrição da imagem aqui

A única coisa que resta a fazer é garantir que o usuário não entre com duas casas decimais. Você pode fazer isso enquanto eles estão editando. Adicione o seguinte código ao seu controlador de visualização. Esse código remove uma segunda casa decimal assim que é typescript. Aparece ao usuário como se o segundo decimal nunca tivesse aparecido em primeiro lugar.

 - (void)viewDidLoad { [super viewDidLoad]; [self.textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; } - (void)textFieldDidChange:(UITextField *)textField { NSString *text = textField.text; NSRange range = [text rangeOfString:@"."]; if (range.location != NSNotFound && [text hasSuffix:@"."] && range.location != (text.length - 1)) { // There's more than one decimal textField.text = [text substringToIndex:text.length - 1]; } } 
 @property (strong) NSNumberFormatter *numberFormatter; @property (strong) NSString *oldStringValue; - (void)awakeFromNib { [super awakeFromNib]; self.numberFormatter = [[NSNumberFormatter alloc] init]; self.oldStringValue = self.stringValue; [self setDelegate:self]; } - (void)controlTextDidChange:(NSNotification *)obj { NSNumber *number = [self.numberFormatter numberFromString:self.stringValue]; if (number) { self.oldStringValue = self.stringValue; } else { self.stringValue = self.oldStringValue; } } 

Tópico antigo, mas vale a pena mencionar que a Apple introduziu o NSRegularExpression no iOS 4.0. (Tomando a expressão regular da resposta de Peter)

 // Look for 0-n digits from start to finish NSRegularExpression *noFunnyStuff = [NSRegularExpression regularExpressionWithPattern:@"^(?:|0|[1-9]\\d*)(?:\\.\\d*)?$" options:0 error:nil]; // There should be just one match if ([noFunnyStuff numberOfMatchesInString:< #theString#> options:0 range:NSMakeRange(0, < #theString#>.length)] == 1) { // Yay, digits! } 

Sugiro armazenar a instância NSRegularExpression algum lugar.

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if(string.length > 0) { NSCharacterSet *numbersOnly = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"]; NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:string]; BOOL stringIsValid = [numbersOnly isSupersetOfSet:characterSetFromTextField]; return stringIsValid; } return YES; } 

Eu queria um campo de texto que permitisse apenas inteiros. Aqui está o que acabei com (usando informações daqui e de outros lugares):

Crie o formatador de número inteiro (em UIApplicationDelegate para que possa ser reutilizado):

 @property (nonatomic, retain) NSNumberFormatter *integerNumberFormatter; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Create and configure an NSNumberFormatter for integers integerNumberFormatter = [[NSNumberFormatter alloc] init]; [integerNumberFormatter setMaximumFractionDigits:0]; return YES; } 

Use o filtro em UITextFieldDelegate:

 @interface MyTableViewController : UITableViewController  { ictAppDelegate *appDelegate; } - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { // Make sure the proposed string is a number NSNumberFormatter *inf = [appDelegate integerNumberFormatter]; NSString* proposedString = [textField.text stringByReplacingCharactersInRange:range withString:string]; NSNumber *proposedNumber = [inf numberFromString:proposedString]; if (proposedNumber) { // Make sure the proposed number is an integer NSString *integerString = [inf stringFromNumber:proposedNumber]; if ([integerString isEqualToString:proposedString]) { // proposed string is an integer return YES; } } // Warn the user we're rejecting the change AudioServicesPlayAlertSound(kSystemSoundID_Vibrate); return NO; } 

Não é tão elegante, mas simples 🙂

 - (BOOL) isNumber: (NSString*)input { return [input doubleValue] != 0 || [input isEqualToString:@"0"] || [input isEqualToString:@"0.0"]; } 

Aceitar valores decimais em campos de texto com um único ponto (.) Trabalhando com o iPad e o iPhone no Swift 3

  func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted let components = string.components(separatedBy: inverseSet) let filtered = components.joined(separator: "") if filtered == string { return true } else { if string == "." { let countdots = textField.text!.components(separatedBy:".").count - 1 if countdots == 0 { return true }else{ if countdots > 0 && string == "." { return false } else { return true } } }else{ return false } } } 

Para ser mais internacional (e não apenas nos Estados Unidos ;-)) basta replace no código acima por

 -(NSNumber *) getNumber { NSString* localeIdentifier = [[NSLocale autoupdatingCurrentLocale] localeIdentifier]; NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: localeIdentifier] ; return [self getNumberWithLocale: [l_en autorelease] ]; } 

Esta resposta usa o NSFormatter como dito anteriormente. Confira:

 @interface NSString (NSNumber) - (BOOL) isNumberWithLocale:(NSLocale *) stringLocale; - (BOOL) isNumber; - (NSNumber *) getNumber; - (NSNumber *) getNumberWithLocale:(NSLocale*) stringLocale; @end @implementation NSString (NSNumber) - (BOOL) isNumberWithLocale:(NSLocale *) stringLocale { return [self getNumberWithLocale:stringLocale] != nil; } - (BOOL) isNumber { return [ self getNumber ] != nil; } - (NSNumber *) getNumber { NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: @"en_US"] ; return [self getNumberWithLocale: [l_en autorelease] ]; } - (NSNumber *) getNumberWithLocale:(NSLocale*) stringLocale { NSNumberFormatter *formatter = [[ [ NSNumberFormatter alloc ] init ] autorelease]; [formatter setLocale: stringLocale ]; return [ formatter numberFromString:self ]; } @end 

Eu espero que isso ajude alguém. =)

  #import "NSString+Extension.h" //@interface NSString (Extension) // //- (BOOL) isAnEmail; //- (BOOL) isNumeric; // //@end @implementation NSString (Extension) - (BOOL) isNumeric { NSString *emailRegex = @"[0-9]+"; NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex]; return [emailTest evaluateWithObject:self]; // NSString *localDecimalSymbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]; // NSMutableCharacterSet *decimalCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:localDecimalSymbol]; // [decimalCharacterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]]; // // NSCharacterSet* nonNumbers = [decimalCharacterSet invertedSet]; // NSRange r = [self rangeOfCharacterFromSet: nonNumbers]; // // if (r.location == NSNotFound) // { // // check to see how many times the decimal symbol appears in the string. It should only appear once for the number to be numeric. // int numberOfOccurances = [[self componentsSeparatedByString:localDecimalSymbol] count]-1; // return (numberOfOccurances > 1) ? NO : YES; // } // else return NO; } 

No Swift 4:

 let formatString = "12345" if let number = Decimal(string:formatString){ print("String contains only number") } else{ print("String doesn't contains only number") } 

Isto abrange: Controle de peças decimais (incluindo o número de casas decimais permitidas), controle de copiar / colar, separadores internacionais.

Passos:

  1. Certifique-se de que seu controlador de visualização herde de UITextFieldDelegate

    class MyViewController: UIViewController, UITextFieldDelegate {…

  2. Em viewDidLoad, defina seu delegado de controle para auto:

    override func viewDidLoad () {super.viewDidLoad (); yourTextField.delegate = self}

  3. Implemente o seguinte método e atualize a constante “decsAllowed” com a quantidade desejada de decimais ou 0 se você quiser um número natural.

Swift 4

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let decsAllowed: Int = 2 let candidateText = NSString(string: textField.text!).replacingCharacters(in: range, with: string) let decSeparator: String = NumberFormatter().decimalSeparator!; let splitted = candidateText.components(separatedBy: decSeparator) let decSeparatorsFound = splitted.count - 1 let decimalPart = decSeparatorsFound > 0 ? splitted.last! : "" let decimalPartCount = decimalPart.characters.count let characterSet = NSMutableCharacterSet.decimalDigit() if decsAllowed > 0 {characterSet.addCharacters(in: decSeparator)} let valid = characterSet.isSuperset(of: CharacterSet(charactersIn: candidateText)) && decSeparatorsFound < = 1 && decsAllowed >= decimalPartCount return valid } 

Se depois você precisar convertê-la com segurança em um número, basta usar o tipo Double (yourstring) ou Int (yourstring) ou a maneira mais acadêmica:

 let formatter = NumberFormatter() let theNumber: NSNumber = formatter.number(from: yourTextField.text)!