检查UITextField的输入是否仅为数字


Answers:


35

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

7
是的,我知道这是一个可怕的老答案,但我认为静态方法的声明如下:+ (BOOL) TextIsValidValue:(NSString*)newText:(double)&value:...
RCIX 2011年

7
TextIsValidValue是静态C函数,这意味着它在文件本地,而不是任何对象的一部分。您(@RCIX)正在描述一种对象方法,它与C ++中的静态方法相似,并且与静态C函数(或与此有关的静态变量!)完全不同。
Peter N Lewis,

该表达式匹配空字符串(非数字)。
Nikolai Ruhe 2012年

通常,为了匹配输入数字,您需要允许使用空字符串,否则用户不能输入例如“ 1 <delete> 2”。
Peter N Lewis

6
对于那些不知道什么是正则表达式或如何工作的开发人员,只需简单地转到此正则表达式解码器,然后复制/粘贴(?:|0|[1-9]\\d*)(?:\\.\\d*)以了解其含义。另请参见Regex Wikipedia
Honey

117

您可以在以下几行中完成此操作:

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

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


22
此答案不检查双打或标点符号
zambono

72

有几种方法可以执行此操作:

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

IMO,使用类似-[NSString doubleValue]将不会是最好的选择,因为两者@"0.0"@"abc"会产生的doubleValue 0的*值的方法都返回0,如果他们不能将字符串正确转换,所以这将是一个很难区分合法字符串@"0"和无效字符串。像C的东西strtol函数将有相同的问题。

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


嗯,我必须为NSNumberFormatter设置了错误的选项。当我使用带字符串“ 34jfkjdskj80”的numberFromString时,它将返回数字3480。似乎只是剥离字符而不返回nil。
Tony Eichelberger,

5
@Tony是的,我不确定您在做什么,因为以下内容为我记录了“ N :(空)”:NSNumberFormatter * f = [[NSNumberFormatter alloc] init]; NSNumber * n = [f numberFromString:@"34jfkjdskj80"]; NSLog(@"N: %@", n);
Dave DeLong

2
这有点旧,但是如果有人正在阅读,我认为应该注意,在解析字符串时NSScanner,像NSNumberFormatter,那样要考虑语言环境,前提是要setLocale:在扫描器对象上使用(例如,可以提供[NSLocale currentLocale])。
dreamlax 2010年

1
有人读过《战争与和平》。其他人则喜欢“白鲸迪克”。就我自己而言,我想我要拉下Stack Overflow数据集,用Dave的答案过滤掉问题,然后享受。
BP。

1
@MarkAmery是的,您可以依靠该行为。尽管可能没有记录,但是从二进制兼容性的角度来看,这是多年来的行为,并且更改它是不可行的。
Dave DeLong

19

如果只允许用户输入数字,则可以使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:或类似方法即可。


13
#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;
}

11

这是结合了Peter Lewis上面的答案(检查UITextField的输入仅是数字)和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]

请提供一个链接,让我可以从中了解更多信息。
Smit Saraiya

4

对于整数测试,它将是:

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

好的答案,但是这种方法的问题仍然是将输入值'232asdfsadf'视为Number。
Whoami 2014年

您可以对原始字符串的整数值(重新转换为字符串)进行长度比较,以确保“ 123aoenuthr”不被视为整数。
Michael

3

您可以像这样使用字符串的doubleValue

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

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


此外,使用库函数通常比滚动自己的库更好。在这种情况下,其他区域性使用逗号作为小数点,并且大概可可库可以处理小数点。
kibibu

更不用说进行字面量浮点数相等比较只是不好的做法
M. Ryan

3

嗨,我遇到了完全相同的问题,但我看不到我以前发布的答案,所以就在这里。

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

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

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

积分: 从NSString中删除除数字以外的所有数字


负数(-)?
CMVR 2013年

3

游戏晚了,但是我在这里使用了一个方便的小类别,用于解释小数位和用于它的本地符号。链接到这里

@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吗?这就是我的用法。
Andrei Radulescu 2014年

不起作用,@“ A”得到的结果是数字YES,但这不是数字
Gank 2015年

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

3

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

在界面构建器中,选择UITextField,转到“属性”检查器,然后将“键盘类型”更改为“十进制填充”。

在此处输入图片说明

这将使键盘如下所示:

在此处输入图片说明

剩下要做的唯一一件事就是确保用户不要输入两位小数。他们可以在编辑时执行此操作。将以下代码添加到您的视图控制器。输入该代码后,它将立即删除第二个小数位。在用户看来,第二个小数从未出现在第一位。

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

1
不要忘记复制和粘贴的能力-在这种情况下您的方法会失败
slxl

1
这并不解决所有情况。用户可以复制粘贴文本或使用蓝牙键盘。

2
@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

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

// 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实例存储在某个地方。


1

我想要一个只允许整数的文本字段。这就是我最终的结果(使用此处和其他位置的信息):

创建整数格式器(在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;
}

1

不太优雅,但是很简单:)

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

1
此解决方案不适用于0.00等无限零。所以我不建议人们使用它
Vinh 2014年

1

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

0

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

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

0

如前所述,此答案使用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

希望对您有所帮助。=)


0
   #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

在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

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

脚步:

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

    类MyViewController:UIViewController,UITextFieldDelegate {...

  2. 在viewDidLoad中,将控件委托设置为self:

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

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

斯威夫特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)!
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.