Bir dizenin sayısal olup olmadığını bulma


93

Bir dizenin sadece sayılardan oluşup oluşmadığını nasıl kontrol edebiliriz? Bir dizeden bir alt dize alıyorum ve bunun sayısal bir alt dize olup olmadığını kontrol etmek istiyorum.

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

Yanıtlar:


241

Dizeyi bir sayı olarak çözümlemeye çalışmanın sınırlı hassasiyetine dayanmayan bir yol:

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

Bak +[NSCharacterSet decimalDigitCharacterSet]ve -[NSString rangeOfCharacterFromSet:].


6
bu @ "231.123" için geçerlidir, bu nedenle: // newString yalnızca 0-9 arasındaki rakamlardan ve .karakterden oluşur
Nicolas Tyler

5
NSMutableCharacterSet * digitsAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitsAndDots addCharactersInString: @ "."]; NSCharacterSet * notDigitsNorDots = [digitsAndDots invertedSet]; // ayrıca, "invertedSet" getirmek için teşekkürler. Varlığını bilmiyordum
2013

5
not: bu yöntem @ "" bir sayı olarak kabul edilir; Mümkünse, [newString length]> 0 olup olmadığını da kontrol etmeniz gerekebilir. Yanılıyorsam lütfen bana bildirin.
markckim

2
@Supertecnoboff Görünüşe göre bu IOS'ta değişen bir şey. Bunun yerine emin olmak için bu kullanılabilir:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
Nicolas Tyler

2
@KMGorbunov NSCharacterSet'in aslında setteki her karakteri içeren bir destek seti sakladığını düşünmüyorum. invertedSetOluşturulduğu kümeyi saran ve tüm sorgular için ters değeri döndüren bir sınıf döndürdüğünden şüpheleniyorum . Ama kesin olarak bilmiyorum.
John Calsbeek

33

NSNumberFormatter sınıfından numberFromString:yöntemi kullanmanızı öneririm , sanki sayı geçersizmiş gibi nil döndürür; aksi takdirde, size bir NSNumarası döndürecektir.

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

Geçerli bir numara döndürmeyeceğinden emin misiniz, örneğin @ "124sbd" için?
Tommy

Hayır, hem NSNumberFormatter hem de NSScanner dizeniz için döndürecektir NO. Ayrıca bilmeye değer: YESboşlukla doldurulmuş sayılar için de dönerler . Btw, cevabınıza biraz gerçek kod pasajı ekledim, umarım aldırmazsınız.
Regexident

NSScanner, "geçerli bir tam sayı gösterimi" bulduktan sonra, dokümantasyona göre bu dizi için "YES" döndürmelidir. Dahası, iOS 4.3.2'de bir testte tam olarak bunu yaptı. Ancak, NSNumberFormatter sıfır döndürdü.
Tommy

Bu "." bu benim için bir gereklilik. @John Calsbeek tarafından gönderilen yanıt güzelce çalıştı.
Damian

Yüzlerce karakterden oluşan bir dizge için ne olur? Oluşturulan NSNumber için bir sınır var mı?
Biniou

12

"^[0-9]+$"Aşağıdaki yöntemle desene göre düzenli ifadeye göre doğrulayın -validateString:withPattern:.

[self validateString:"12345" withPattern:"^[0-9]+$"];
  1. "123.123" kabul edilirse
    • Desen ile "^[0-9]+(.{1}[0-9]+)?$"
  2. Tam olarak 4 basamaklı sayılar ise ".".
    • Desenli "^[0-9]{4}$".
  3. Olmayan rakam sayıları varsa "."ve uzunluk 2 ~ 5 arasındaysa.
    • Desenli "^[0-9]{2,5}$".
  4. Eksi işaretiyle: "^-?\d+$"

Normal ifade , çevrimiçi web sitesinde kontrol edilebilir .

Yardımcı işlev aşağıdaki gibidir.

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

Oyun alanında test edin.

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 için böyle denedim 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 }ve hata aldımPlayground execution aborted: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
Mathi Arasan

Hızlı için doğru olanı bilmiyorum 3. Yanlışsam düzeltin.
Mathi Arasan

Ne dersinreturn matchRange.location != NSNotFound;
LimeRed

eksi işareti ne olacak?
Thomas

@Thomas With ^-?\d+$, sitede doğruladım: regex101.com
AechoLiu

9

Bir NSScanner oluşturabilir ve basitçe dizeyi tarayabilirsiniz:

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

Check out NSScanner belgelerine seçim için daha yöntemleri için.


Bu size en azından ilk karakterin sayısal olup olmadığını söylemez mi?
Tommy

Benim hatam. Son aramayı unuttum isAtEnd.
Regexident

6

Belirli bir dizedeki her karakterin sayısal olduğunu kontrol etmenin en kolay yolu muhtemelen şudur:

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

Kabul edilebilir karakterler üzerinde tam kontrol istiyorsanız, diğer NSCharacterSet fabrika yöntemlerinden birini kullanın.


Bu yolu beğendim. Çok temiz görünmese de, NSString'de "rakam olmayanlar" olup olmadığını kontrol etmenin çok kolay ve temel bir temel dostu yoludur. + Diğer robot tabanlı yöntemlerden çok daha hızlı olduğunu düşünüyorum (muhtemelen burada performansa pek bakmasak da).
nembleton

StringByTrimmingCharactersInSet'in yalnızca String'in başlangıcını ve sonunu kırdığına inanıyorum
Brody Robertson

@BrodyRobertson: öyle. Bu cevap için en ufak bir önemi yok. Sizce bu test hangi örnek için başarısız olur?
Tommy

@Tommy, Yeniden değerlendirdikten sonra cevabınızı anlıyorum ve geçerli ve olumlu oy vereceğim, ancak yeniden seçmeme izin vermek için düzenlemeniz gerekiyor
Brody Robertson

6

Bu orijinal soru Objective-C hakkındaydı, ancak Swift duyurulmadan yıllar önce de yayınlandı. Öyleyse, buraya Google'dan geliyorsanız ve Swift kullanan bir çözüm arıyorsanız, işte burada:

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

Dizenin yalnızca rakamlara sahip olduğunu doğrulamanız gerekiyorsa Swift 3 çözümü:

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

1
Temiz ve güzel, en iyi çözüm. Bunun gereksiz .invertedve başka eylemler yapmamasını seviyorum .
Dannie P

4

Açık olmak gerekirse, dizelerdeki tamsayılar için bu işlevler.

Bu, John'un yukarıdaki cevabına dayanan küçük bir yardımcı kategori:

.h dosyasında

@interface NSString (NumberChecking)

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

@end

.m dosyasında

#import "NSString+NumberChecking.h"

@implementation NSString (NumberChecking)

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

@end

kullanım:

#import "NSString+NumberChecking.h"

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

4

Swift 3 çözümü şöyle olabilir:

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'in cevabının bir uzantısı ve @Jeff ve @gyratory circus'un yorumlarının açıklaması.

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

Aşağıdakiler kategori yöntemleri olarak eklenebilir: 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'in cevabı neredeyse doğrudur ancak bazı Unicode uç durumlarını atlar.

Başına belgelerinedecimalDigitCharacterSet , bu seti olarak Unicode göre kategorize tüm karakterleri içerir Nd. Böylece cevapları, diğerleri arasında kabul edecektir:

  • (U + 0967 DEVANAGARI DIGIT ONE)
  • (U + 1811 MONGOLIAN DIGIT ONE)
  • 𝟙 (U + 1D7D9 MATEMATİKSEL ÇİFT YAPILI RAKAM BİR)

Bir anlamda bu doğru olsa da - her karakter Ndbir ondalık basamağa eşlenir - bu neredeyse kesinlikle soruyu soranın beklediği şey değildir. Bu yazı itibariyle 610 kod noktasıNd vardır, bunlardan sadece on tanesi beklenen karakterler 0(U + 0030) ile 9(U + 0039) arasıdır.

Sorunu çözmek için, kabul edilebilir olan karakterleri tam olarak belirtmeniz yeterlidir:

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

1

Yine başka bir seçenek:

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

Kullanım örneği:

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

0

Bir dizenin bir sayı olup olmadığını test edin Yararlı Olabilir

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

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

0

Swift uzantısı:

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 için

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

0

Karma dillerden gelen , 0-9 basamak biçimlerini kullanan (veya kullanmayan) rakamlarınız olduğunda, herhangi bir sayıyı arayacak bir normal ifade çalıştırmanız gerekir, sonraki şey tüm rakamları 0- olacak şekilde dönüştürmektir. 9 format (gerçek değere ihtiyacınız varsa):

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

En kolay ve en güvenilir yol, Doublesonuç şu ise nil- yasal bir sayıya dönüştürülemezmiş gibi göstermeye çalışmaktır.

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]

Belgelerde daha fazla bilgi: https://developer.apple.com/documentation/swift/double/2926277-init


0

Simple, dize uzantısını yazdı:

extension String {
    var isNumeric: Bool {
        return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.