การค้นหาว่าสตริงเป็นตัวเลขหรือไม่


93

เราจะตรวจสอบได้อย่างไรว่าสตริงประกอบด้วยตัวเลขเท่านั้น ฉันกำลังดึงสตริงย่อยออกจากสตริงและต้องการตรวจสอบว่าเป็นสตริงย่อยที่เป็นตัวเลขหรือไม่

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

คำตอบ:


242

นี่เป็นวิธีหนึ่งที่ไม่ต้องอาศัยความแม่นยำที่ จำกัด ในการพยายามแยกวิเคราะห์สตริงเป็นตัวเลข:

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 * digitAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitAndDots addCharactersInString: @ "."]; NSCharacterSet * notDigitsNorDots = [digitAndDots invertedSet]; // นอกจากนี้ขอขอบคุณสำหรับการนำเข้า "invertedSet" ฉันไม่รู้เกี่ยวกับการมีอยู่ของมัน
codrut

5
หมายเหตุ: วิธีนี้ถือว่า @ "" เป็นตัวเลข หากเป็นไปได้คุณอาจต้องตรวจสอบ [newString lenght]> 0 ด้วยโปรดแจ้งให้เราทราบหากฉันคิดผิด
markckim

2
@Supertecnoboff ดูเหมือนว่านี่จะเป็นสิ่งที่เปลี่ยนแปลงใน IOS สามารถใช้แทนได้:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
Nicolas Tyler

2
@KMGorbunov ฉันไม่คิดว่า NSCharacterSet กำลังจัดเก็บชุดสำรองที่มีอักขระทุกตัวในชุดจริงๆ ฉันสงสัยว่าinvertedSetกำลังส่งคืนคลาสที่ห่อชุดที่สร้างแบบฟอร์มและส่งคืนค่าตรงกันข้ามสำหรับการสืบค้นทั้งหมด แต่ฉันไม่รู้แน่ชัด
John Calsbeek

33

ฉันขอแนะนำให้ใช้numberFromString:วิธีการจากคลาสNSNumberFormatterราวกับว่าตัวเลขไม่ถูกต้องมันจะคืนค่าศูนย์ มิฉะนั้นจะส่งคืน 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 กลับไม่มีค่า
Tommy

สิ่งนี้ไม่จับ "." ซึ่งเป็นข้อกำหนดสำหรับฉัน คำตอบจาก @John Calsbeek ทำงานได้ดี
Damian

จะเกิดอะไรขึ้นกับสตริงที่มีอักขระหลายร้อยตัว มีการ จำกัด NSNumber หรือไม่?
Biniou

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:

ทดสอบในสนามเด็กเล่น

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 แก้ไขฉันถ้าฉันผิด
คณิตอรสนธิ์

แค่นั้นreturn matchRange.location != NSNotFound;
ล่ะ

แล้วเครื่องหมายลบล่ะ?
โทมัส

@ โทมัสด้วย^-?\d+$ฉันตรวจสอบแล้วบนเว็บไซต์: regex101.com
AechoLiu

9

คุณสามารถสร้าง NSScanner และสแกนสตริง:

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

ตรวจสอบเอกสารของ NSScannerสำหรับวิธีการเพิ่มเติมให้เลือก


นั่นจะไม่เพียงบอกคุณว่าอย่างน้อยอักขระตัวแรกเป็นตัวเลขหรือไม่?
Tommy

ความผิดฉันเอง. isAtEndลืมสายสุดท้ายที่จะ
Regexident

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 จะจดเฉพาะจุดเริ่มต้นและจุดสิ้นสุดของ String เท่านั้น
Brody Robertson

@BrodyRobertson: มันทำ ซึ่งสำคัญไม่น้อยสำหรับคำตอบนี้ ตัวอย่างใดที่คุณคิดว่าการทดสอบนี้จะล้มเหลว
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และอื่น ๆ
Dannie P

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

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 's คำตอบและการชี้แจงของ@ Jeffและคณะละครสัตว์ @gyratory ' s ความคิดเห็น

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

2

คำตอบของ John Calsbeekนั้นเกือบจะถูกต้อง แต่ละเว้นกรณีขอบ Unicode บางส่วน

ตามเอกสารdecimalDigitCharacterSetชุดที่มีตัวอักษรทั้งหมดแบ่งตาม Unicode Ndเป็น ดังนั้นคำตอบของพวกเขาจะยอมรับในหมู่คนอื่น ๆ :

  • (ยู + 0967 เดวานาการีดิจิทัล)
  • (U + 1811 MONGOLIAN DIGIT ONE)
  • 𝟙 (U + 1D7D9 คณิตศาสตร์สองชั้นหลักหนึ่ง)

ในขณะที่ในแง่หนึ่งสิ่งนี้ถูกต้อง - อักขระแต่ละตัวใน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]+$"];

0

ทดสอบว่าสตริงเป็นตัวเลขหรือไม่อาจเป็นประโยชน์

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

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

0

ส่วนขยาย 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

สำหรับ 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

วิธีที่ง่ายที่สุดและน่าเชื่อถือที่สุดคือการพยายามร่ายราวกับ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

Simple เขียนนามสกุลสตริง:

extension String {
    var isNumeric: Bool {
        return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.