【问题标题】:Check that a input to UITextField is numeric only检查 UITextField 的输入是否仅为数字
【发布时间】:2010-11-22 03:51:52
【问题描述】:

如何验证UITextField 的字符串输入?我想检查字符串是否为数字,包括小数点。

【问题讨论】:

    标签: objective-c cocoa-touch validation nsstring uitextfield


    【解决方案1】:

    你可以用这样的几行来完成:

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

    -- 这是为了验证输入是否仅为数字字符。查看NSCharacterSet 的文档以了解其他选项。您可以使用 characterSetWithCharactersInString 来指定任何一组有效的输入字符。

    【讨论】:

    • 这个答案不检查双打或标点符号
    【解决方案2】:

    有几种方法可以做到这一点:

    1. 使用 NSNumberFormatter 的 numberFromString: 方法。如果它可以正确解析字符串,这将返回一个 NSNumber,如果不能,则返回 nil
    2. 使用 NSScanner
    3. 剥离任何非数字字符,看看字符串是否仍然匹配
    4. 使用正则表达式

    IMO,使用类似 -[NSString doubleValue] 的东西不是最好的选择,因为 @"0.0"@"abc" 的 doubleValue 都为 0。如果 *value 方法无法转换字符串正确,因此很难区分@"0" 的合法字符串和无效字符串。类似 C 的 strtol 函数也会有同样的问题。

    我认为使用 NSNumberFormatter 是最好的选择,因为它考虑了语言环境(即欧洲的数字 @"1,23",而美国的数字 @"1.23")。

    【讨论】:

    • 嗯,我必须为 NSNumberFormatter 设置错误的选项。当我使用字符串“34jfkjdskj80”使用 numberFromString 时,它将返回数字 3480。似乎只是去除字符而不是返回 nil。
    • @Tony 是的,我不确定你在做什么,因为以下日志为我“N: (null)”:NSNumberFormatter * f = [[NSNumberFormatter alloc] init]; NSNumber * n = [f numberFromString:@"34jfkjdskj80"]; NSLog(@"N: %@", n);
    • 这有点老了,但如果有人正在阅读这篇文章,我认为应该注意NSScanner,如NSNumberFormatter,在解析字符串时会考虑语言环境,前提是您在扫描仪对象上使用setLocale:(例如,您可以提供[NSLocale currentLocale])。
    • 有些人读《战争与和平》。其他人更喜欢“白鲸记”。我自己,我想我只是要拉下 Stack Overflow 数据集,用 Dave 的答案过滤掉问题,然后尽情享受吧。
    • @MarkAmery 是的,您可以依赖这种行为。尽管它可能没有记录在案,但它多年来一直如此,从二进制兼容性的角度来看,改变它是不可行的。
    【解决方案3】:

    我在我的 Mac 应用程序中使用此代码,相同或相似的代码应该适用于 iPhone。它基于 RegexKitLite 正则表达式,当文本无效时将文本变为红色。

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

    【讨论】:

    • 是的,这是一个非常古老的答案,我知道,但我认为静态方法是这样声明的:+ (BOOL) TextIsValidValue:(NSString*)newText:(double)&value:...
    • TextIsValidValue 是一个静态 C 函数,这意味着它是文件的本地函数,而不是任何对象的一部分。您(@RCIX)正在描述一个对象方法,它类似于 C++ 中的静态方法,并且与静态 C 函数(或就此而言的静态变量!)是完全不同的概念。
    • 表达式匹配空字符串(不是数字)。
    • 一般情况下,要匹配一个数字输入,需要允许空字符串,否则用户不能输入,例如输入“12”。
    • 对于那些不知道 regex 是什么或它们如何工作的开发人员,只需转到this regex decoder wesbite 并复制/粘贴(?:|0|[1-9]\\d*)(?:\\.\\d*) 以了解其含义。另见Regex Wikipedia
    【解决方案4】:

    如果你希望用户只被允许输入数字,你可以让你的 ViewController 实现 UITextFieldDelegate 的一部分并定义这个方法:

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

    可能有更有效的方法,但我发现这是一种非常方便的方法。而且该方法应该很容易适应验证双打或其他:只需使用 scanDouble: 或类似的。

    【讨论】:

      【解决方案5】:
      #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;
      }
      

      【讨论】:

        【解决方案6】:

        这里有一些将 Peter Lewis 上面的答案 (Check that a input to UITextField is numeric only) 与 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]
        

        【讨论】:

        • 请给我一个链接,我可以从中了解更多信息。
        【解决方案7】:

        对于整数测试,它将是:

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

        【讨论】:

        • 不错的答案,但这种方法的问题仍然是输入值“232asdfsadf”,被视为数字。
        • 您可以将 integerValue(重新转换为字符串)与原始字符串进行长度比较,以确保“123aoenuthr”不被视为整数。
        【解决方案8】:

        你可以使用你的字符串的 doubleValue 像

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

        我认为如果字符串无效,这将返回 a 作为 0.0(它可能会引发异常,在这种情况下您可以捕获它,文档说 0.0 tho)。更多信息here

        【讨论】:

        • 另外,使用库函数通常比滚动你自己的要好。在这种情况下,其他文化使用逗号作为小数点,大概 Cocoa 库可以处理。
        • 更不用说进行文字浮点相等比较只是不好的做法
        【解决方案9】:

        您好,遇到了完全相同的问题,我没有看到我发布的答案,所以在这里。

        我通过 IB 创建并连接了我的文本字段。当我通过 Control+Drag 将它连接到我的代码时,我选择了 Action,然后选择了 Editing Changed 事件。这会在每个字符条目上触发该方法。您可以使用不同的事件来适应。

        之后,我用这个简单的代码替换了文本。请注意,我创建了自己的字符集以包含小数/句点字符和数字。基本上将无效字符上的字符串分开,然后用空字符串重新加入。

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

        学分: Remove all but numbers from NSString

        【讨论】:

        • 负数 (-)?
        【解决方案10】:

        游戏迟到了,但我在这里使用了一个方便的小类别,它说明了小数位和用于它的本地符号。链接到它的要点here

        @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
        

        【讨论】:

        • 在isNumeric中alphanumericCharacterSet不应该是decimalDigitCharacterSet吗?我就是这样使用它的。
        • 不行,@"A" 得到结果是Numeric YES,但不是数字
        【解决方案11】:
        - (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;
        }
        

        【讨论】:

          【解决方案12】:

          IMO 实现目标的最佳方式是显示数字键盘而不是普通键盘。这限制了用户可以使用哪些密钥。这减轻了进行验证的需要,更重要的是它可以防止用户犯错误。数字键盘也更适合输入数字,因为键要大得多。

          在界面生成器中选择 UITextField,进入 Attributes Inspector 并将“Keyboard Type”更改为“Decimal Pad”。

          这将使键盘看起来像这样:

          剩下要做的唯一事情是确保用户没有输入两位小数。您可以在他们编辑时执行此操作。将以下代码添加到您的视图控制器。此代码在输入后立即删除第二个小数位。在用户看来,就好像第 2 位小数一开始就没有出现过一样。

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

          【讨论】:

          • 不要忘记复制和粘贴能力——在这种情况下你的方法会失败
          • 这并不能解决所有情况。用户可以复制粘贴文本或使用蓝牙键盘。
          【解决方案13】:
          @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;
            }
          }
          

          【讨论】:

            【解决方案14】:

            旧线程,但值得一提的是,Apple 在 iOS 4.0 中引入了NSRegularExpression。 (从彼得的回应中取正则表达式)

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

            我建议将NSRegularExpression 实例存储在某处。

            【讨论】:

              【解决方案15】:

              我想要一个只允许整数的文本字段。这是我最终得到的结果(使用来自这里和其他地方的信息):

              创建整数格式化程序(在 UIApplicationDelegate 中以便可以重复使用):

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

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

              【讨论】:

                【解决方案16】:

                不那么优雅,但简单:)

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

                【讨论】:

                • 此解决方案不适用于像 0.00 这样的无限零。所以我不会建议人们使用它
                【解决方案17】:

                在带有单个 (.) 点的文本字段中接受十进制值,在 Swift 3 中使用 iPad 和 iPhone

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

                【讨论】:

                  【解决方案18】:

                  为了更加国际化(而不仅仅是美国色;-))只需在上面的代码中替换为

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

                  【讨论】:

                    【解决方案19】:

                    如前所述,此答案使用 NSFormatter。看看吧:

                    @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
                    

                    我希望它可以帮助某人。 =)

                    【讨论】:

                      【解决方案20】:
                         #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;
                          }
                      

                      【讨论】:

                        【解决方案21】:

                        在 Swift 4 中:

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

                        【讨论】:

                          【解决方案22】:

                          这包括:小数部分控制(包括允许的小数位数)、复制/粘贴控制、国际分隔符。

                          步骤:

                          1. 确保您的视图控制器继承自 UITextFieldDelegate

                            类 MyViewController: UIViewController, UITextFieldDelegate {...

                          2. 在 viewDidLoad 中,将您的控制委托设置为 self:

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

                          3. 实现以下方法并使用所需的小数位数更新“decsAllowed”常量,如果需要自然数,则更新为 0。

                          斯威夫特 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
                          }
                          

                          如果之后您需要将该字符串安全地转换为数字,您可以使用 Double(yourstring) 或 Int(yourstring) 类型转换,或者更学术的方式:

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

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-07-25
                            • 2011-07-13
                            • 2023-03-27
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多