Mencari tahu apakah string itu numerik atau tidak


93

Bagaimana kita bisa memeriksa apakah sebuah string terdiri dari angka saja. Saya mengambil substring dari string dan ingin memeriksa apakah itu substring numerik atau bukan.

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

Jawaban:


241

Berikut salah satu cara yang tidak bergantung pada ketepatan terbatas dalam mencoba mengurai string sebagai angka:

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

Lihat +[NSCharacterSet decimalDigitCharacterSet]dan -[NSString rangeOfCharacterFromSet:].


6
ini berlaku untuk @ "231.123" jadi: // newString hanya terdiri dari angka 0 sampai 9 dan .karakter
Nicolas Tyler

5
NSMutableCharacterSet * digitsAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitsAndDots addCharactersInString: @ "."]; NSCharacterSet * notDigitsNorDots = [digitsAndDots invertedSet]; // juga, thanx untuk memasukkan "invertedSet". Saya tidak tahu tentang keberadaannya
codrut

5
catatan: metode ini menganggap @ "" sebagai angka; jika memungkinkan, Anda mungkin juga perlu memeriksa [panjangString baru]> 0. beri tahu saya jika saya salah.
markckim

2
@Supertecnoboff Sepertinya ini adalah sesuatu yang telah berubah di iOS. Ini dapat digunakan sebagai gantinya untuk memastikan:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
Nicolas Tyler

2
@KMGorbunov Saya tidak berpikir bahwa NSCharacterSet sebenarnya menyimpan set dukungan yang berisi setiap karakter dalam set. Saya menduga invertedSetmengembalikan kelas yang membungkus set yang dibuatnya bentuk, dan mengembalikan nilai yang berlawanan untuk semua kueri. Tapi saya tidak tahu pasti.
John Calsbeek

33

Saya sarankan menggunakan numberFromString:metode dari kelas NSNumberFormatter , seolah-olah nomor tersebut tidak valid, itu akan mengembalikan nil; jika tidak, ini akan mengembalikan Anda NSNumber.

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

Apakah Anda yakin itu tidak akan mengembalikan nomor yang valid misalnya untuk @ "124sbd"?
Tommy

Tidak, NSNumberFormatter dan NSScanner akan kembali NOuntuk string Anda. Juga perlu diketahui: mereka juga mengembalikan YESangka yang diisi dengan spasi. Btw, saya baru saja menambahkan beberapa cuplikan kode aktual ke jawaban Anda, harap Anda tidak keberatan.
Regexident

NSScanner harus mengembalikan 'YES' untuk string itu, sesuai dokumentasi, setelah menemukan "representasi integer yang valid". Selanjutnya, ia melakukan persis seperti itu dalam pengujian di iOS 4.3.2. Namun, NSNumberFormatter mengembalikan nihil.
Tommy

Ini tidak menangkap '.' yang merupakan persyaratan bagi saya. Jawaban dari @John Calsbeek bekerja dengan baik.
Damian

Apa yang terjadi untuk string dengan ratusan karakter semua digit? Apakah ada batasan untuk NSNumber yang dibuat?
Biniou

11

Validasi dengan ekspresi reguler, berdasarkan pola "^[0-9]+$", dengan metode berikut -validateString:withPattern:.

[self validateString:"12345" withPattern:"^[0-9]+$"];
  1. Jika "123.123" dianggap
    • Dengan pola "^[0-9]+(.{1}[0-9]+)?$"
  2. Jika tepat 4 digit angka, tanpa ".".
    • Dengan pola "^[0-9]{4}$".
  3. Jika digit angka tanpa ".", dan panjangnya antara 2 ~ 5.
    • Dengan pola "^[0-9]{2,5}$".
  4. Dengan tanda minus: "^-?\d+$"

Ekspresi reguler dapat diperiksa di situs web online .

Fungsi helper adalah sebagai berikut.

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

Versi Swift 3:

Uji di taman bermain.

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)

Saya mencoba seperti ini untuk 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 }Dan saya mendapat kesalahanPlayground execution aborted: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
Mathi Arasan

Saya tidak tahu yang benar untuk swift 3. Koreksi saya jika saya salah.
Mathi Arasan

Bagaimana kalau sajareturn matchRange.location != NSNotFound;
LimeRed

bagaimana dengan tanda minus?
Thomas

@ Thomas Dengan ^-?\d+$, saya memverifikasinya di situs: regex101.com
AechoLiu

9

Anda dapat membuat NSScanner dan cukup memindai string:

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

Lihat dokumentasi NSScanner untuk metode lainnya yang dapat dipilih.


Bukankah itu hanya memberi tahu Anda apakah setidaknya karakter pertama adalah numerik?
Tommy

Salahku. Lupa panggilan terakhir ke isAtEnd.
Regexident

6

Saya pikir cara termudah untuk memeriksa bahwa setiap karakter dalam string yang diberikan adalah numerik mungkin:

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

Gunakan salah satu metode pabrik NSCharacterSet lainnya jika Anda ingin kontrol penuh atas karakter yang dapat diterima.


Saya suka cara ini. Meskipun tampaknya tidak terlalu bersih, ini adalah cara yang sangat mudah dan ramah pondasi inti untuk memeriksa apakah ada "non-digit" di NSString. + Saya pikir ini jauh lebih cepat daripada cara berbasis robot lainnya (meskipun kami mungkin tidak banyak melihat kinerja di sini).
nembleton

Saya percaya bahwa stringByTrimmingCharactersInSet hanya memangkas awal dan akhir String
Brody Robertson

@BrodyRobertson: ya. Yang tidak penting sedikit pun untuk jawaban ini. Menurut Anda, contoh apa yang akan gagal dalam pengujian ini?
Tommy

@Tommy, Setelah mengevaluasi ulang saya mengerti jawaban Anda dan itu valid dan akan memberi suara positif tetapi Anda perlu mengedit agar saya dapat memberi suara ulang
Brody Robertson

6

Pertanyaan asli ini tentang Objective-C, tetapi juga diposting bertahun-tahun sebelum Swift diumumkan. Jadi, jika Anda datang ke sini dari Google dan mencari solusi yang menggunakan Swift, ini dia:

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

Solusi Swift 3 jika perlu memverifikasi bahwa string hanya memiliki angka:

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

1
Bersih dan bagus, solusi terbaik. Saya suka bahwa ini tidak melakukan .invertedtindakan yang tidak perlu dan lainnya.
Dannie P

4

agar jelas, ini berfungsi untuk integer dalam string.

berikut adalah kategori penolong kecil berdasarkan jawaban John di atas:

dalam file .h

@interface NSString (NumberChecking)

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

@end

dalam file .m

#import "NSString+NumberChecking.h"

@implementation NSString (NumberChecking)

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

@end

pemakaian:

#import "NSString+NumberChecking.h"

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

4

Solusi Swift 3 bisa seperti:

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

Jawaban John Calsbeek hampir benar tetapi menghilangkan beberapa kasus tepi Unicode.

Menurut dokumentasi untukdecimalDigitCharacterSet , set itu mencakup semua karakter yang dikategorikan oleh Unicode sebagai Nd. Dengan demikian jawaban mereka akan diterima, antara lain:

  • (U + 0967 DEVANAGARI DIGIT SATU)
  • (U + 1811 MONGOLIAN DIGIT SATU)
  • 𝟙 (U + 1D7D9 MATEMATIKA DOUBLE-STRUCK DIGIT SATU)

Meskipun dalam beberapa hal ini benar - setiap karakter di Ndmemang dipetakan ke digit desimal - hampir pasti tidak seperti yang diharapkan penanya. Pada tulisan ini ada 610 poin kode yang dikategorikan sebagaiNd , hanya sepuluh di antaranya adalah karakter yang diharapkan 0(U + 0030) hingga 9(U + 0039).

Untuk memperbaiki masalah, cukup tentukan dengan tepat karakter yang dapat diterima:

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

1

Namun opsi lain:

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

Contoh penggunaan:

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

1

Perpanjangan @ John Calsbeek 'jawaban s, dan klarifikasi @ Jeff dan sirkus @gyratory ' s komentar.

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

Berikut ini dapat ditambahkan sebagai metode kategori untuk 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

Menguji apakah sebuah string adalah angka Mungkin Bermanfaat

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

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

0

Ekstensi 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

Untuk Swift 3

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

0

Jika Anda memiliki digit yang berasal dari bahasa campuran , yang menggunakan (atau tidak) format 0-9 digit, Anda perlu menjalankan regex yang akan mencari angka apa pun, selanjutnya adalah mengubah semua digit menjadi 0- 9 format (jika Anda membutuhkan nilai sebenarnya):

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

Cara termudah dan paling andal adalah mencoba menggunakan Double, jika hasilnya nil- tidak dapat dibentuk menjadi angka yang sah.

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]

Info lebih lanjut di dokumentasi: https://developer.apple.com/documentation/swift/double/2926277-init


0

Sederhana aja ekstensi stringnya:

extension String {
    var isNumeric: Bool {
        return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.