Tìm hiểu xem một chuỗi có phải là số hay không


93

Làm thế nào chúng ta có thể kiểm tra xem một chuỗi chỉ được tạo thành từ các số. Tôi đang lấy ra một chuỗi con từ một chuỗi và muốn kiểm tra xem nó có phải là một chuỗi con số hay không.

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

Câu trả lời:


241

Đây là một cách không dựa vào độ chính xác hạn chế khi cố gắng phân tích cú pháp chuỗi thành một số:

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

Xem +[NSCharacterSet decimalDigitCharacterSet]-[NSString rangeOfCharacterFromSet:].


6
điều này đúng với @ "231.123" vì vậy: // newString chỉ bao gồm các chữ số từ 0 đến 9 và .ký tự
Nicolas Tyler

5
NSMutableCharacterSet * digitAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitAndDots addCharactersInString: @ "."]; NSCharacterSet * notDigitsNorDots = [digitAndDots invertedSet]; // còn nữa, thanx vì đã nhập "invertedSet". Tôi không biết về sự tồn tại của nó
codrut

5
lưu ý: phương pháp này coi @ "" là một số; nếu có, bạn cũng có thể cần kiểm tra [newString lenght]> 0. Vui lòng cho tôi biết nếu tôi sai.
markckim

2
@Supertecnoboff Có vẻ như đây là một cái gì đó đã thay đổi trong IOS. Điều này có thể được sử dụng thay để đảm bảo:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
Nicolas Tyler

2
@KMGorbunov Tôi không nghĩ rằng NSCharacterSet thực sự đang lưu trữ một tập hợp sao lưu chứa mọi ký tự trong tập hợp. Tôi nghi ngờ invertedSetđang trả về một lớp bao bọc tập hợp mà nó đã được tạo biểu mẫu và trả về giá trị ngược lại cho tất cả các truy vấn. Nhưng tôi không biết chắc chắn.
John Calsbeek

33

Tôi khuyên bạn nên sử dụng numberFromString:phương thức từ lớp NSNumberFormatter , như thể số không hợp lệ, nó sẽ trả về nil; nếu không, nó sẽ trả về cho bạn một Số NSN.

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

Bạn có chắc chắn rằng nó sẽ không trả về một số hợp lệ, ví dụ: @ "124sbd"?
Tommy

Không, cả NSNumberFormatter và NSScanner sẽ trả về NOcho chuỗi của bạn. Cũng đáng biết: chúng cũng trả về YEScho các số được đệm bằng khoảng trắng. Btw, tôi vừa thêm một số đoạn mã thực tế vào câu trả lời của bạn, hy vọng bạn không phiền.
Regexident

NSScanner phải trả về 'CÓ' cho chuỗi đó, theo tài liệu, sau khi tìm thấy "biểu diễn số nguyên hợp lệ". Hơn nữa, nó đã làm chính xác điều đó trong một thử nghiệm trên iOS 4.3.2. Tuy nhiên, NSNumberFormatter đã trả về con số không.
Tommy

Điều này không bắt được '.' đó là một yêu cầu đối với tôi. Câu trả lời từ @John Calsbeek rất hiệu quả.
Damian

Điều gì xảy ra đối với một chuỗi có hàng trăm ký tự tất cả là chữ số? Có giới hạn nào cho Số NSN được tạo không?
Biniou

11

Xác thực bằng biểu thức chính quy, theo mẫu "^[0-9]+$", với phương pháp sau -validateString:withPattern:.

[self validateString:"12345" withPattern:"^[0-9]+$"];
  1. Nếu "123.123" được coi là
    • Với mẫu "^[0-9]+(.{1}[0-9]+)?$"
  2. Nếu số chính xác 4 chữ số, không có ".".
    • Với hoa văn "^[0-9]{4}$".
  3. Nếu các số không có chữ số "."và độ dài từ 2 ~ 5.
    • Với hoa văn "^[0-9]{2,5}$".
  4. Với dấu trừ: "^-?\d+$"

Biểu thức chính quy có thể được kiểm tra trong trang web trực tuyến .

Chức năng trợ giúp như sau.

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

Phiên bản Swift 3:

Thử nghiệm trong sân chơi.

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)

Tôi đã cố gắng như thế này cho 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 }Và tôi đã nhận lỗiPlayground execution aborted: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
Mathi Arasan

Tôi không biết câu đó đúng cho nhanh 3. Hãy sửa cho tôi nếu tôi sai.
Mathi Arasan

Làm thế nào về chỉreturn matchRange.location != NSNotFound;
LimeRed

còn dấu trừ thì sao?
Thomas

@Thomas With ^-?\d+$, tôi đã xác minh nó trên trang web: regex101.com
AechoLiu

9

Bạn có thể tạo một NSScanner và chỉ cần quét chuỗi:

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

Xem tài liệu của NSScanner để biết thêm các phương pháp để lựa chọn.


Điều đó sẽ không chỉ cho bạn biết liệu ít nhất ký tự đầu tiên có phải là số không?
Tommy

Lỗi của tôi. Quên cuộc gọi cuối cùng đến isAtEnd.
Regexident

6

Tôi nghĩ cách dễ nhất để kiểm tra xem mọi ký tự trong một chuỗi nhất định là số có lẽ là:

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

Sử dụng một trong các phương pháp gốc NSCharacterSet khác nếu bạn muốn kiểm soát hoàn toàn các ký tự được chấp nhận.


Tôi thích cách này. Mặc dù nó có vẻ không được sạch sẽ cho lắm, nhưng đây là một cách rất dễ dàng và thân thiện với nền tảng để kiểm tra xem có "không phải chữ số" trong NSString hay không. + Tôi nghĩ rằng nó nhanh hơn nhiều so với bất kỳ cách dựa trên robot nào khác (mặc dù có lẽ chúng tôi không xem xét nhiều về hiệu suất ở đây).
nembleton,

Tôi tin rằng stringByTrimmingCharactersInSet chỉ Trims những bắt đầu và kết thúc của chuỗi
Brody Robertson

@BrodyRobertson: nó có. Điều này không quan trọng chút nào cho câu trả lời này. Bạn nghĩ thử nghiệm này sẽ thất bại vì ví dụ nào?
Tommy

@Tommy, Sau khi đánh giá lại, tôi hiểu câu trả lời của bạn và nó hợp lệ và sẽ ủng hộ nhưng bạn cần bạn chỉnh sửa để cho phép tôi sửa đổi
Brody Robertson

6

Câu hỏi ban đầu này là về Objective-C, nhưng nó cũng đã được đăng nhiều năm trước khi Swift được công bố. Vì vậy, nếu bạn đến đây từ Google và đang tìm kiếm một giải pháp sử dụng Swift, thì đây là cách:

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

Giải pháp Swift 3 nếu cần xác minh rằng chuỗi chỉ có các chữ số:

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

1
Sạch sẽ và tốt đẹp, giải pháp tốt nhất. Tôi thích rằng điều này không làm không cần thiết .invertedvà các hành động khác.
Dannie P

4

để rõ ràng, chức năng này đối với các số nguyên trong chuỗi.

có một danh mục trợ giúp nhỏ dựa trên câu trả lời của John ở trên:

trong tệp .h

@interface NSString (NumberChecking)

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

@end

trong tệp .m

#import "NSString+NumberChecking.h"

@implementation NSString (NumberChecking)

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

@end

sử dụng:

#import "NSString+NumberChecking.h"

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

4

Giải pháp Swift 3 có thể giống như:

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

Câu trả lời của John Calsbeek gần đúng nhưng bỏ qua một số trường hợp cạnh Unicode.

Theo tài liệu chodecimalDigitCharacterSet , bộ đó bao gồm tất cả các ký tự được phân loại bởi Unicode như Nd. Vì vậy, câu trả lời của họ sẽ được chấp nhận, trong số những người khác:

  • (U + 0967 DEVANAGARI SỐ MỘT)
  • (U + 1811 MONGOLIAN DIGIT ONE)
  • 𝟙 (SỐ ĐÔI ĐÔI-STRUCK MỘT MÔN TOÁN U + 1D7D9)

Mặc dù theo một nghĩa nào đó, điều này đúng - mỗi ký tự trong Ndánh xạ tới một chữ số thập phân - nó gần như chắc chắn không phải là những gì người hỏi mong đợi. Tính đến thời điểm viết bài này, có 610 điểm mã được phân loạiNd , chỉ có mười trong số đó là các ký tự mong đợi 0(U + 0030) đến9 (U + 0039).

Để khắc phục sự cố, chỉ cần chỉ định chính xác những ký tự có thể chấp nhận được:

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

1

Tuy nhiên, một lựa chọn khác:

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

Ví dụ sử dụng:

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

1

Một phần mở rộng của @ John Calsbeek 'câu trả lời, và làm rõ @ Jeffxiếc @gyratory ' s ý kiến.

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

Sau đây có thể được thêm vào làm các phương pháp danh mục cho 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

Kiểm tra xem một chuỗi là một số Có thể hữu ích

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

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

0

Tiện ích mở rộng 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
}  }

0

Đối với Swift 3

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

0

Khi bạn có các chữ số từ các ngôn ngữ hỗn hợp , sử dụng (hoặc không) các định dạng chữ số 0-9, bạn sẽ cần chạy một regex sẽ tìm kiếm bất kỳ số nào, điều tiếp theo là chuyển đổi tất cả các chữ số thành 0- 9 định dạng (nếu bạn cần giá trị thực):

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

Cách dễ nhất và đáng tin cậy nhất là cố gắng truyền Double, nếu kết quả là nil- nó không thể được tạo thành một số hợp pháp.

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]

Thông tin thêm trong tài liệu: https://developer.apple.com/documentation/swift/double/2926277-init


0

Đơn giản đã viết phần mở rộng chuỗi:

extension String {
    var isNumeric: Bool {
        return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.