判断字符串是否为数字

95

怎样判断一个字符串是否全部由数字组成。我从一个字符串中取出了一个子字符串,现在想检查它是否是一个数值型的子串。

NSString *newString = [myString substringWithRange:NSMakeRange(2,3)];
19个回答

246

这里有一种方法不依赖于尝试将字符串解析为数字的有限精度:

NSCharacterSet* notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([newString rangeOfCharacterFromSet:notDigits].location == NSNotFound)
{
    // newString consists only of the digits 0 through 9
}

请参阅+[NSCharacterSet decimalDigitCharacterSet]-[NSString rangeOfCharacterFromSet:]


6
对于@"231.123"来说是正确的,因此:// newString 只包含数字0到9和字符. - string.Empty
6
NSMutableCharacterSet *digitsAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitsAndDots addCharactersInString:@"."]; NSCharacterSet *notDigitsNorDots = [digitsAndDots invertedSet]; //感谢您提到“invertedSet”,我之前不知道它的存在 - codrut
5
注意:此方法认为 @"" 是一个数字;如果适用,您可能还需要检查 [newString length] > 0。如果我有错误,请告诉我。 - markckim
3
@Supertecnoboff 看起来这是IOS中的一些变化。可以使用以下代码以确保正确性:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]] - string.Empty
2
@KMGorbunov 我认为 NSCharacterSet 并没有实际存储包含集合中每个字符的后备集。我怀疑 invertedSet 返回的是一个类,该类包装了它所创建的集合,并对所有查询返回相反的值。但我并不确定。 - John Calsbeek
显示剩余9条评论

35

我建议使用NSNumberFormatter类中的numberFromString:方法,因为如果数字无效,它将返回nil;否则,它将返回NSNumber。

NSNumberFormatter *nf = [[[NSNumberFormatter alloc] init] autorelease];
BOOL isDecimal = [nf numberFromString:newString] != nil;

你确定它不会返回一个有效的数字,例如@"124sbd"吗? - Tommy
不,无论是NSNumberFormatter还是NSScanner都会针对您的字符串返回“NO”。值得注意的是:它们也会将用空格填充的数字返回“YES”。顺便说一句,我只是在您的答案中添加了一些实际的代码片段,希望您不介意。 - Regexident
根据文档,NSScanner应该返回该字符串的'YES',因为它找到了“有效的整数表示”。此外,在iOS 4.3.2上进行的测试中,它确实做到了这一点。然而,NSNumberFormatter返回了nil。 - Tommy
这不包括".",而这对我来说是必需的。@John Calsbeek的答案效果很好。 - Damian
一个由数百个数字字符组成的字符串会发生什么?创建的NSNumber是否有限制? - Biniou
最佳答案是扫描仪(参见Regexident的答案),它也适用于数字字符串(格式化程序对像-1.2这样的数字不起作用)。 - Thomas

12

使用正则表达式验证,使用模式"^[0-9]+$",使用以下方法-validateString:withPattern:

[self validateString:"12345" withPattern:"^[0-9]+$"];
  1. 如果"123.123"被认为是
    • 匹配模式为"^[0-9]+(.{1}[0-9]+)?$"
  2. 如果是恰好由4个数字组成,没有"."
    • 匹配模式为"^[0-9]{4}$"
  3. 如果是没有"."的数字,且长度在2到5之间。
    • 匹配模式为"^[0-9]{2,5}$"
  4. 带负号的数字: "^-?\d+$"

正则表达式可以在在线网站中进行检查。

辅助函数如下。

// Validate the input string with the given pattern and
// return the result as a boolean
- (BOOL)validateString:(NSString *)string withPattern:(NSString *)pattern
{
    NSError *error = nil;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];

    NSAssert(regex, @"Unable to create regular expression");

    NSRange textRange = NSMakeRange(0, string.length);
    NSRange matchRange = [regex rangeOfFirstMatchInString:string options:NSMatchingReportProgress range:textRange];

    BOOL didValidate = NO;

    // Did we find a matching range
    if (matchRange.location != NSNotFound)
        didValidate = YES;

    return didValidate;
}

Swift 3版本:

在playground中测试。


import UIKit
import Foundation

func validate(_ str: String, pattern: String) -> Bool {
    if let range = str.range(of: pattern, options: .regularExpression) {
        let result = str.substring(with: range)
        print(result)
        return true
    }
    return false
}

let a = validate("123", pattern: "^-?[0-9]+")
print(a)

我尝试了Swift 3的以下代码:func numberOnly(string: String) -> Int { let expression = "" let regex = NSRegularExpression.init(pattern: expression, options: .caseInsensitive) let numberOfMatches = regex.numberOfMatches(in: string, options: .reportProgress, range: NSRange.init(location: 0, length: string.characters.count)) if numberOfMatches == 0 { return Int(string)! } return 0 } 但是我得到了错误信息:Playground execution aborted: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0). - Mathi Arasan
我不知道Swift 3的正确版本。如果我错了,请纠正我。 - Mathi Arasan
那就只返回 return matchRange.location != NSNotFound; 好了。 - LimeRed
减号怎么办? - Thomas
@Thomas 我用 ^-?\d+$ 在 https://regex101.com 网站上验证了一下。 - AechoLiu

9

您可以创建一个 NSScanner,然后简单地扫描字符串:

NSDecimal decimalValue;
NSScanner *sc = [NSScanner scannerWithString:newString];
[sc scanDecimal:&decimalValue];
BOOL isDecimal = [sc isAtEnd];

请查看NSScanner的文档以获取更多可供选择的方法。


这难道不仅仅告诉你第一个字符是否是数字吗? - Tommy
我的错。忘记最后调用isAtEnd - Regexident

7

我认为检查给定字符串中的每个字符都是数字的最简单方法可能是:

NSString *trimmedString = [newString stringByTrimmingCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]];

if([trimmedString length])
{
    NSLog(@"some characters outside of the decimal character set found");
}
else
{
    NSLog(@"all characters were in the decimal character set");
}

如果你想完全控制可接受的字符,可以使用其他NSCharacterSet工厂方法之一。


我喜欢这种方式。虽然它看起来不是很干净,但这是一种非常简单和核心基础友好的方法,用于检查NSString中是否存在“非数字”字符。此外,我认为它比任何其他基于机器人的方法都要快得多(尽管我们可能在这里对性能没有太多关注)。 - nembleton
我相信 stringByTrimmingCharactersInSet 只会修剪字符串的开头和结尾。 - Brody Robertson
@BrodyRobertson:确实如此。但对于这个答案来说,这并不重要。你认为这个测试会失败的例子是什么? - Tommy
@Tommy,经过重新评估,我理解了你的答案,它是有效的,我会点赞,但你需要编辑一下让我可以重新投票。 - Brody Robertson

7

如果需要验证字符串是否只包含数字,可以使用Swift 3的以下解决方案:

CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: myString))

1
清晰简洁,是最佳的解决方案。我喜欢它不会执行不必要的.inverted和其他操作。 - Dannie P
超级干净的解决方案,真的很喜欢! - Alexandre Odet

6

这个问题最初是关于Objective-C的,但它也是在Swift发布多年之前发布的。因此,如果您从Google来到这里并正在寻找使用Swift的解决方案,那么请看以下内容:

let testString = "12345"
let badCharacters = NSCharacterSet.decimalDigitCharacterSet().invertedSet

if testString.rangeOfCharacterFromSet(badCharacters) == nil {
    print("Test string was a number")
} else {
    print("Test string contained non-digit characters.")
}

4

Swift 3的解决方案可能如下:

extension String {

    var doubleValue:Double? {
        return NumberFormatter().number(from:self)?.doubleValue
    }

    var integerValue:Int? {
        return NumberFormatter().number(from:self)?.intValue
    }

    var isNumber:Bool {
        get {
            let badCharacters = NSCharacterSet.decimalDigits.inverted
            return (self.rangeOfCharacter(from: badCharacters) == nil)
        }
    }
}

4

为了明确,此功能适用于字符串中的整数。

这是一个基于John上面的答案的小助手类别:

在.h文件中

@interface NSString (NumberChecking)

+(bool)isNumber:(NSString *)string;

@end

在.m文件中

#import "NSString+NumberChecking.h"

@implementation NSString (NumberChecking)

+(bool)isNumber {
    if([self rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location == NSNotFound) {
        return YES;
    }else {
        return NO;
    }
}

@end

用法:

#import "NSString+NumberChecking.h"

if([someString isNumber]) {
    NSLog(@"is a number");
}else {
    NSLog(@"not a number");
}

2

这是对@John Calsbeek回答的延伸,并澄清了@Jeff@gyratory circus的评论。涉及到IT技术相关内容。

+ (BOOL)doesContainDigitsOnly:(NSString *)string
{
    NSCharacterSet *nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];

    BOOL containsDigitsOnly = [string rangeOfCharacterFromSet:nonDigits].location == NSNotFound;

    return containsDigitsOnly;
}

+ (BOOL)doesContainNonDigitsOnly:(NSString *)string
{
    NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];

    BOOL containsNonDigitsOnly = [string rangeOfCharacterFromSet:digits].location == NSNotFound;

    return containsNonDigitsOnly;
}

以下内容可以作为类方法添加到 NSString 中:
- (BOOL)doesContainDigitsOnly
{
    NSCharacterSet *nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];

    BOOL containsDigitsOnly = [self rangeOfCharacterFromSet:nonDigits].location == NSNotFound;

    return containsDigitsOnly;
}

- (BOOL)doesContainNonDigitsOnly
{
    NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];

    BOOL containsNonDigitsOnly = [self rangeOfCharacterFromSet:digits].location == NSNotFound;

    return containsNonDigitsOnly;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接