Vérifier qu'une entrée à UITextField est numérique seulement

comment valider la chaîne de caractères entrée dans un UITextField ? Je veux vérifier que la chaîne est numérique, y compris les points décimaux.

81
demandé sur Josh Caswell 2009-08-24 06:57:24

22 réponses

j'utilise ce code dans mon application Mac, le même ou similaire devrait fonctionner avec l'iPhone. Il est basé sur les expressions régulières RegexKitLite et rend le texte rouge lorsqu'il est invalide.

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]];
    }
}
34
répondu Peter N Lewis 2009-09-02 20:24:59

Vous pouvez le faire en quelques lignes comme ceci:

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

-- ceci est pour valider l'entrée est des caractères numériques seulement. Consultez la documentation pour NSCharacterSet pour les autres options. Vous pouvez utiliser characterSetWithCharactersInString pour spécifier tout ensemble de caractères d'entrée valides.

115
répondu Donal O'Danachair 2012-07-21 10:04:57

il y a plusieurs façons de faire cela:

  1. utiliser le numéro Nsnumberformatter's number fromstring: method. Ceci retournera un nombre NSN s'il peut analyser la chaîne correctement, ou nil s'il ne peut pas.
  2. Use NSScanner
  3. rayer tout caractère non numérique et voir si la chaîne de caractères correspond toujours
  4. utiliser une expression régulière

IMO, en utilisant quelque chose comme -[NSString doubleValue] ne serait pas la meilleure option parce que les deux @"0.0" et @"abc" auront une valeur double de 0. Les méthodes *value toutes retournent 0 si elles ne sont pas capables de convertir la chaîne correctement, il serait donc difficile de faire la distinction entre une chaîne légitime de @"0" et une chaîne non valide. Quelque chose comme la fonction strtol de C aurait le même problème.

je pense que l'utilisation de NSNumberFormatter serait la meilleure option, car il prend locale dans compte (ie, le nombre @"1,23" en Europe, contre @"1.23" aux Etats-Unis).

71
répondu Dave DeLong 2009-08-24 04:09:05

si vous voulez qu'un utilisateur soit seulement autorisé à entrer des chiffres, vous pouvez faire votre ViewController implémenter une partie de UITextFieldDelegate et définir cette méthode:

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

il y a probablement des moyens plus efficaces, mais je trouve que c'est une jolie pratique . Et la méthode doit être facilement adaptable à la validation des doubles ou autre: il suffit d'utiliser scanDouble: ou similaire.

19
répondu Frank Shearar 2009-11-17 18:36:26
#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;
}
13
répondu kalpesh jetani 2011-07-07 14:15:31

voici quelques-uns de ceux qui combinent la réponse de Peter Lewis ci-dessus ( vérifier qu'une entrée à UITextField est numérique seulement ) avec 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]
11
répondu Sai Ramachandran 2017-05-23 12:25:27

pour le test entier ce sera:

- (BOOL) isIntegerNumber: (NSString*)input
{
    return [input integerValue] != 0 || [input isEqualToString:@"0"];
}
4
répondu zvjerka24 2012-12-26 15:32:41

vous pouvez utiliser la double valeur de votre chaîne comme

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

je pense que cela va retourner un as 0.0 si la chaîne est invalide (il pourrait jeter une exception, dans ce cas, vous pouvez juste l'attraper, les docs disent 0.0 tho). en savoir plus ici

3
répondu Daniel 2012-07-21 09:58:59

Hi avait exactement le même problème et je ne vois pas la réponse que j'ai utilisé posté, donc voici.

j'ai créé et connecté mon champ de texte via IB. Lorsque je l'ai connecté à mon code via Control+Drag, j'ai choisi Action, puis j'ai sélectionné L'événement D'édition modifié. Cela déclenche la méthode sur chaque entrée de caractère. Vous pouvez utiliser un événement différent pour convenir.

ensuite, j'ai utilisé ce code simple pour remplacer le texte. Notez que j'ai créé mon propre personnage défini pour inclure le caractère décimal / période et les nombres. Sépare fondamentalement la chaîne sur les caractères invalides, puis les rejoint avec la chaîne vide.

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

crédits: supprimer tous les numéros sauf ceux de la NSString

"
3
répondu guptron 2017-05-23 11:54:11

en retard au jeu mais voici une petite catégorie pratique que j'utilise qui explique les décimales et le symbole local utilisé pour elle. lien vers son gist ici

@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
3
répondu bennythemink 2014-08-04 03:43:48

IMO le meilleur moyen d'atteindre votre objectif est d'afficher un clavier numérique plutôt que le clavier normal. Cela restreint les clés qui sont disponibles à l'utilisateur. Cela réduit le besoin de faire de la validation, et plus important encore, il empêche l'utilisateur de faire une erreur. Le pavé numérique est également beaucoup plus agréable pour entrer des nombres parce que les clés sont beaucoup plus grandes.

dans interface builder sélectionnez L'UITextField, allez à L'Inspecteur des attributs et changez le "Type de clavier "à"bloc décimal".

enter image description here

qui fera ressembler le clavier à ceci:

enter image description here

la seule chose à faire est de s'assurer que l'utilisateur n'entre pas deux décimales. Tu peux faire ça pendant qu'ils éditent. Ajoutez le code suivant à votre contrôleur de vue. Ce code supprime une deuxième décimale la place dès qu'il est entré. Il apparaît à l'utilisateur comme si la 2ème décimale n'est jamais apparu dans la première place.

- (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];
  }
}
3
répondu David 2015-10-09 16:07:57
@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;
  }
}
2
répondu StuFF mc 2011-11-28 20:31:40

vieux fil, mais il est intéressant de mentionner que Apple a introduit NSRegularExpression dans iOS 4.0. (En prenant l'expression régulière à partir de Pierre de réponse)

// 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!
}

je suggère de stocker l'instance NSRegularExpression quelque part.

2
répondu Can 2014-03-26 22:04:32
- (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;
}
2
répondu Hsm 2015-07-29 03:19:34

je voulais un champ de texte qui ne permettait entiers. Voici ce que j'ai fini par dire (en utilisant des informations d'ici et d'ailleurs):

Créer un nombre entier formateur (en UIApplicationDelegate de sorte qu'il peut être réutilisé):

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

utiliser un filtre dans UITextFieldDelegate:

@interface MyTableViewController : UITableViewController <UITextFieldDelegate> {
    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;
}
1
répondu Symmetric 2012-01-18 03:05:01

pas si élégant, mais simple:)

- (BOOL) isNumber: (NSString*)input
{
    return [input doubleValue] != 0 || [input isEqualToString:@"0"] || [input isEqualToString:@"0.0"];
}
1
répondu zvjerka24 2012-12-26 15:30:43

Accepter les valeurs décimales dans les champs de texte avec un seul (.) dot travaille avec iPad et iPhone dans 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
            }
        }
    }
1
répondu Raj Joshi 2017-01-19 08:53:42

Pour être plus à l'international (et pas seulement NOUS, de couleur ;-) ) il suffit de remplacer dans le code ci-dessus par

-(NSNumber *) getNumber
{
  NSString* localeIdentifier = [[NSLocale autoupdatingCurrentLocale] localeIdentifier];
  NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: localeIdentifier] ;
  return [self getNumberWithLocale: [l_en autorelease] ];
}
0
répondu user1458963 2012-07-21 10:03:15

cette réponse utilise NSFormatter comme dit précédemment. Check it out:

@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

j'espère que ça aidera quelqu'un. = )

0
répondu Leandro 2012-07-21 10:03:56
   #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;
    }
0
répondu Gank 2015-06-01 09:04:33

Dans Swift 4:

let formatString = "12345"
if let number = Decimal(string:formatString){

    print("String contains only number")
}
else{
    print("String doesn't contains only number")
}
0
répondu Ankit garg 2017-10-13 21:25:54

couvre: le contrôle de la partie décimale (y compris le nombre de décimales autorisées), le contrôle de la copie/pâte, les séparateurs internationaux.

Suit:

  1. assurez-vous que votre contrôleur de vue hérite de UITextFieldDelegate

    class MyViewController: UIViewController, UITextFieldDelegate {...

  2. Dans le viewDidLoad, définissez votre contrôle délégué à moi-même:

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

  3. implémentez la méthode suivante et mettez à jour la constante" decsAllowed " avec la quantité désirée de décimales ou 0 si vous voulez un nombre naturel.

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
}

si après vous avez besoin de convertir en toute sécurité cette chaîne en un nombre, vous pouvez juste utiliser Double(votre corde) ou Int (votre corde) cast, ou la manière plus académique:

let formatter = NumberFormatter()
let theNumber: NSNumber = formatter.number(from: yourTextField.text)!
0
répondu Jorge Ramírez 2017-10-17 12:50:08