判断一个字符串是不是为数字
Posted
技术标签:
【中文标题】判断一个字符串是不是为数字【英文标题】:Finding out whether a string is numeric or not判断一个字符串是否为数字 【发布时间】:2011-05-22 23:04:56 【问题描述】:我们如何检查字符串是否仅由数字组成。我正在从字符串中取出一个子字符串,并想检查它是否是数字子字符串。
NSString *newString = [myString substringWithRange:NSMakeRange(2,3)];
【问题讨论】:
【参考方案1】:这是一种不依赖于尝试将字符串解析为数字的有限精度的方法:
NSCharacterSet* notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([newString rangeOfCharacterFromSet:notDigits].location == NSNotFound)
// newString consists only of the digits 0 through 9
请参阅 +[NSCharacterSet decimalDigitCharacterSet]
和 -[NSString rangeOfCharacterFromSet:]
。
【讨论】:
@"231.123" 是这样的: // newString 只包含数字 0 到 9 和.
字符
NSMutableCharacterSet *digitsAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitsAndDots addCharactersInString:@"."]; NSCharacterSet *notDigitsNorDots = [digitsAndDots reverseSet]; //另外,感谢引入“invertedSet”。我不知道它的存在
注意:此方法将@"" 视为一个数字;如果适用,您可能还需要检查 [newString lenght] > 0。如果我错了,请告诉我。
@Supertecnoboff 这似乎在 ios 中有所改变。这可以用来确定:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
@KMGorbunov 我不认为 NSCharacterSet 实际上存储了一个包含集合中每个字符的支持集。我怀疑invertedSet
正在返回一个类,该类包装了它创建的集合形式,并为所有查询返回相反的值。但我不确定。【参考方案2】:
我建议使用NSNumberFormatter 类中的numberFromString:
方法,如果数字无效,它将返回nil;否则,它会返回一个 NSNumber。
NSNumberFormatter *nf = [[[NSNumberFormatter alloc] init] autorelease];
BOOL isDecimal = [nf numberFromString:newString] != nil;
【讨论】:
你确定它不会返回一个有效的数字,例如对于@“124sbd”? 不,NSNumberFormatter 和 NSScanner 都会为您的字符串返回NO
。同样值得知道的是:他们还返回YES
用于填充空格的数字。顺便说一句,我只是在你的答案中添加了一些实际的代码 sn-p,希望你不介意。
NSScanner 应该为该字符串返回“YES”,根据文档,找到“有效的整数表示”。此外,它在 iOS 4.3.2 上的测试中也确实做到了这一点。但是,NSNumberFormatter 确实返回 nil。
这不会捕获 '.'这是对我的要求。 @John Calsbeek 的回答效果很好。
对于所有数字都有数百个字符的字符串会发生什么?创建的 NSNumber 有限制吗?【参考方案3】:
通过正则表达式验证,通过模式"^[0-9]+$"
,使用以下方法-validateString:withPattern:
。
[self validateString:"12345" withPattern:"^[0-9]+$"];
-
如果考虑“123.123”
带图案
"^[0-9]+(.1[0-9]+)?$"
如果正好是 4 位数字,则没有 "."
。
带有模式"^[0-9]4$"
。
如果数字没有"."
,长度在2~5之间。
带有图案"^[0-9]2,5$"
。
带减号:"^-?\d+$"
正则表达式可以在the online web site中查看。
辅助函数如下。
// 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).
我不知道正确的 swift 3。如果我错了,请纠正我。
return matchRange.location != NSNotFound;
怎么样
减号呢?
@Thomas 和^-?\d+$
,我在网站上验证了它:regex101.com【参考方案4】:
您可以创建一个 NSScanner 并简单地扫描字符串:
NSDecimal decimalValue;
NSScanner *sc = [NSScanner scannerWithString:newString];
[sc scanDecimal:&decimalValue];
BOOL isDecimal = [sc isAtEnd];
查看NSScanner's documentation 了解更多可供选择的方法。
【讨论】:
这不是告诉你至少第一个字符是否是数字吗? 我的错。忘了最后一次打电话给isAtEnd
。【参考方案5】:
我认为检查给定字符串中的每个字符是否都是数字的最简单方法可能是:
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 中是否存在“非数字”。 + 我认为它比任何其他基于机器人的方式都快得多(尽管我们在这里可能不太关注性能)。 我相信 stringByTrimmingCharactersInSet 只会修剪字符串的开头和结尾 @BrodyRobertson:确实如此。对于这个答案,这一点都不重要。你认为这个测试会失败的例子是什么? @Tommy,重新评估后,我理解您的回答,它是有效的并且会投票,但您需要您进行编辑以允许我重新投票【参考方案6】:如果需要验证字符串是否只有数字,Swift 3 解决方案:
CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: myString))
【讨论】:
干净漂亮,最好的解决方案。我喜欢这不会做不必要的.inverted
和其他操作。
超干净的解决方案,很喜欢!【参考方案7】:
这个最初的问题是关于 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.")
【讨论】:
【参考方案8】: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)
【讨论】:
【参考方案9】:要清楚,这个函数用于字符串中的整数。
根据上面约翰的回答,这是一个小助手类别:
在.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");
【讨论】:
【参考方案10】:@John Calsbeek 的回答的扩展,以及 @Jeff 和 的澄清@gyratory circus 的 cmets。
+ (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;
【讨论】:
【参考方案11】:John Calsbeek's answer 几乎是正确的,但忽略了一些 Unicode 边缘情况。
根据documentation for decimalDigitCharacterSet
,该集合包括按Unicode 分类为Nd
的所有字符。因此,除其他外,他们的答案将接受:
१
(U+0967 天城数字一)
᠑
(U+1811 蒙古文数字一)
?
(U+1D7D9 数学双击数字一)
虽然在某种意义上这是正确的——Nd
中的每个字符都映射到十进制数字——但几乎可以肯定这不是提问者所期望的。在撰写本文时,有 610 code points categorized as 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
【讨论】:
【参考方案12】:另一种选择:
- (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]+$"];
【讨论】:
【参考方案13】:测试一个字符串是否为数字可能会有帮助
int i = [@"12.3" rangeOfCharacterFromSet: [ [NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet] ].location;
if (i == NSNotFound)
//is a number
【讨论】:
【参考方案14】:Swift 扩展:
extension NSString
func isNumString() -> Bool
let numbers = NSCharacterSet(charactersInString: "0123456789.").invertedSet
let range = self.rangeOfCharacterFromSet(numbers).location
if range == NSNotFound
return true
return false
【讨论】:
【参考方案15】:对于 Swift 3
var onlyDigits: CharacterSet = CharacterSet.decimalDigits.inverted
if testString.rangeOfCharacter(from: onlyDigits) == nil
// String only consist digits 0-9
【讨论】:
【参考方案16】:如果您有来自mixed languages 的数字,使用(或不使用)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
【讨论】:
【参考方案17】:最简单和最可靠的方法是尝试转换为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
【讨论】:
【参考方案18】:简单写了字符串扩展:
extension String
var isNumeric: Bool
return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
【讨论】:
以上是关于判断一个字符串是不是为数字的主要内容,如果未能解决你的问题,请参考以下文章