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)];
Abhinav
sumber

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:].

John Calsbeek
sumber
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;
Sam Symons
sumber
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)
AechoLiu
sumber
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.

Regexident
sumber
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.

Tommy
sumber
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.")
}
TwoStraws
sumber
6

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

CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: myString))
plamkata__
sumber
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");
}
MrTristan
sumber
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)
        }
    }
}
hhamm
sumber
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
}
ravron
sumber
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]+$"];
LuisCien
sumber
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;
}
Abdurrahman Mubeen Ali
sumber
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
}
Ashok Kumar
sumber
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
}  }
Bhavesh Patel
sumber
0

Untuk Swift 3

var onlyDigits: CharacterSet = CharacterSet.decimalDigits.inverted
if testString.rangeOfCharacter(from: onlyDigits) == nil {
  // String only consist digits 0-9
}
Mert Celik
sumber
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
}
OhadM
sumber
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

Ariel
sumber
0

Sederhana aja ekstensi stringnya:

extension String {
    var isNumeric: Bool {
        return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}
Umair Ali
sumber