找出字符串是否为数字


93

我们如何检查字符串是否仅由数字组成。我正在从字符串中取出一个子字符串,并想检查它是否是数字子字符串。

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

Answers:


241

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

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和.字符
Nicolas Tyler

5
NSMutableCharacterSet * digitsAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitsAndDots addCharactersInString:@“。”]; NSCharacterSet * notDigitsNorDots = [digitsAndDots reverseSet]; //此外,thanx用于引入“ invertedSet”。我不知道它的存在
codrut 2013年

5
注意:此方法将@“”视为数字;如果适用,您可能还需要检查[newString长度]>0。如果我错了,请告诉我。
markckim

2
@Supertecnoboff似乎这是IOS中发生的更改。可以使用它来确保:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
Nicolas Tyler

2
@KMGorbunov我不认为NSCharacterSet实际上存储了包含该集中每个字符的后备集。我怀疑invertedSet返回的类包装了它创建的表单集,并为所有查询返回相反的值。但是我不确定。
John Calsbeek

33

我建议使用NSNumberFormatter类中的numberFromString:方法,好像该数字无效,它将返回nil。否则,它将返回一个NSNumber。

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

您确定它不会返回有效的数字,例如@“ 124sbd”吗?
汤米

不,NSNumberFormatter和NSScanner都将返回NO您的字符串。同样值得一提的是:它们还会返回YES用空格填充的数字。顺便说一句,我只是在您的答案中添加了一些实际的代码片段,希望您不要介意。
2011年

根据文档,NSScanner应该在找到“有效的整数表示形式”后对该字符串返回“ YES”。此外,它确实在iOS 4.3.2上的测试中做到了这一点。但是,NSNumberFormatter确实返回nil。
汤米

这不会捕捉到“。” 这是我的要求。@John Calsbeek的回答很好。
Damian 2012年

几百个全数字字符的字符串会发生什么情况?创建的NSNumber是否有限制?
比尼乌(Biniou)

11

"^[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版本:

在操场上测试。

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

我不知道该如何迅速纠正3。如果我做错了,请纠正我。
Mathi Arasan

怎么样return matchRange.location != NSNotFound;
LimeRed

减号呢?
托马斯

@Thomas With ^-?\d+$,我在以下网站上进行了验证:regex101.com
AechoLiu

9

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

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

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


难道不只是告诉您至少第一个字符是数字吗?
汤米

我的错。忘记了对的最后通话isAtEnd
2011年

6

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

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:是的。对于这个答案,哪一点都不重要。您认为该测试会失败的示例是什么?
2015年

@Tommy,经过重新评估后,我理解您的回答,并且它是有效的,并且会投票赞成,但是您需要编辑才能允许我投票
Brody Robertson

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.")
}

6

如果需要验证字符串仅包含数字,则使用Swift 3解决方案:

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

1
干净漂亮,最好的解决方案。我喜欢这样做不会做不必要的.inverted动作。
丹妮·P

4

需要明确的是,此函数用于字符串中的整数。

根据上述约翰的回答,这是一个小帮手类别:

在.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");
}

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

2

John Calsbeek的答案几乎是正确的,但是省略了一些Unicode边缘情况。

根据的文档decimalDigitCharacterSet,该集合包括按Unicode分类为的所有字符Nd。因此,他们的回答将被接受,其中包括:

  • (U + 0967 DEVANAGARI数字一)
  • (U + 1811蒙古文数字一位)
  • 𝟙 (U + 1D7D9数学双打击数字1)

从某种意义上讲这是正确的-每个字符Nd都映射到一个十进制数字-几乎可以肯定,这不是提问者所期望的。截至撰写本文时,共有610个代码点,分类为Nd,其中只有十个是期望的字符0(U + 0030)至9(U + 0039)。

要解决此问题,只需完全指定可接受的字符即可:

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

1

另一个选择:

- (BOOL)isValidNumber:(NSString*)text regex:(NSString*)regex {
    @try {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
        return [predicate evaluateWithObject:text];
    }
    @catch (NSException *exception) {
        assert(false); 
        return NO;
    }
}

用法示例:

BOOL isValid = [self isValidNumber:@"1234" regex:@"^[0-9]+$"];

1

@John Calsbeek的答案的扩展 ,以及@Jeff@gyratory马戏团的注释的澄清。

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

0

测试字符串是否为数字可能会有帮助

int i = [@"12.3" rangeOfCharacterFromSet: [ [NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet] ].location;

if (i == NSNotFound) {
     //is a number
}

0

迅速扩展:

extension NSString {
func isNumString() -> Bool {
    let numbers = NSCharacterSet(charactersInString: "0123456789.").invertedSet
    let range = self.rangeOfCharacterFromSet(numbers).location
    if range == NSNotFound {
        return true
    }
    return false
}  }

0

对于Swift 3

var onlyDigits: CharacterSet = CharacterSet.decimalDigits.inverted
if testString.rangeOfCharacter(from: onlyDigits) == nil {
  // String only consist digits 0-9
}

0

如果您使用的是混合语言的数字(使用(或不使用)0-9数字格式),则需要运行一个正则表达式来查找任何数字,下一步是将所有数字转换为0- 9种格式(如果需要实际值):

// Will look for any language digits
let regex = try NSRegularExpression(pattern: "[^[:digit:]]", options: .caseInsensitive)
let digitsString = regex.stringByReplacingMatches(in: string,
                                                         options: NSRegularExpression.MatchingOptions(rawValue: 0),
                                                         range: NSMakeRange(0, string.count), withTemplate: "")
// Converting the digits to be 0-9 format
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "EN")
let finalValue = numberFormatter.number(from: digitsString)

if let finalValue = finalValue {
  let actualValue = finalValue.doubleValue
}

0

最简单,最可靠的方法是尝试将as强制转换为Double,如果结果为nil-无法将其转换为合法数字。

let strings = ["test", "123", "123.2", "-123", "123-3", "123..22", ".02"]
let validNumbers = strings.compactMap(Double.init)

print(validNumbers)
// prints [123.0, 123.2, -123.0, 0.02]

文档中的更多信息:https : //developer.apple.com/documentation/swift/double/2926277-init


0

简单写了字符串扩展名:

extension String {
    var isNumeric: Bool {
        return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}
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.