З'ясування, чи є рядок числовим чи ні


93

Як ми можемо перевірити, чи рядок складається лише з чисел. Я виймаю підрядку з рядка і хочу перевірити, чи є це числова підрядка чи ні.

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

Відповіді:


241

Ось один із способів, який не покладається на обмежену точність спроби розбору рядка як числа:

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 і .символу
Ніколя Тайлер

5
NSMutableCharacterSet * digitsAndDots = [NSMutableCharacterSet decimalDigitCharacterSet]; [digitsAndDots addCharactersInString: @ "."]; NSCharacterSet * notDigitsNorDots = [digitsAndDots invertedSet]; // також подяка за введення "invertedSet". Я не знав про його існування
codrut

5
примітка: цей метод розглядає @ "" як число; за необхідності, можливо, вам доведеться також перевірити [newString lenght]> 0. будь ласка, повідомте мене, якщо я помиляюся.
markckim

2
@Supertecnoboff Здається, це щось змінилося в IOS. Натомість це можна використовувати, щоб бути впевненим:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
Ніколас Тайлер

2
@KMGorbunov Я не думаю, що NSCharacterSet насправді зберігає резервний набір, який містить кожен окремий символ у наборі. Я підозрюю invertedSet, що повертає клас, який обгортає набір, який він створив, і повертає протилежне значення для всіх запитів. Але я точно не знаю.
Джон Калсбек,

33

Я б запропонував використовувати numberFromString:метод із класу NSNumberFormatter , оскільки якщо число не є дійсним, воно поверне нуль; в іншому випадку він поверне вам номер NS.

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

Ви впевнені, що він не поверне дійсний номер, наприклад для @ "124sbd"?
Томмі

Ні, як NSNumberFormatter, так і NSScanner повернуть NOдля вашого рядка. Також варто знати: вони також повертаються YESза номерами, заповненими пробілами. До речі, я щойно додав до вашої відповіді фактичний фрагмент коду, сподіваюся, ви не проти.
Regexident

NSScanner повинен повернути "ТАК" для цього рядка відповідно до документації, знайшовши "дійсне цілочисельне представлення". Крім того, він зробив саме це в тесті на iOS 4.3.2. Однак NSNumberFormatter повернув нуль.
Томмі

Це не вловлює '.' що є вимогою для мене. Відповідь від @John Calsbeek працював гарно.
Даміан

Що відбувається з рядком із сотнями символів із усіх цифр? Чи існує обмеження для створеного NSNumber?
Biniou

11

Перевірити регулярним виразом, за зразком "^[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).
Маті Арасан

Я не знаю того правильного для швидкого 3. Виправте мене, якщо я помиляюся.
Маті Арасан,

Як би простоreturn matchRange.location != NSNotFound;
LimeRed

як щодо знака мінус?
Томас

@Thomas With ^-?\d+$, я перевірив це на сайті: regex101.com
AechoLiu

9

Ви можете створити сканер NSS і просто відсканувати рядок:

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

Перегляньте документацію NSScanner, щоб дізнатись більше способів на вибір.


Хіба це не просто підкаже, чи принаймні перший символ є числовим?
Томмі

Моє ліжко. Забув остаточний дзвінок до isAtEnd.
Регексидент

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 обрізає лише початок і кінець рядка
Броді Робертсон,

@BrodyRobertson: це так. Що має значення не найменше для цієї відповіді. Як ви думаєте, для якого прикладу цей тест не пройшов би?
Томмі,

@Tommy, після переоцінки я розумію вашу відповідь, вона є дійсною і проголосує, але вам потрібно відредагувати, щоб дозволити мені відкликати
Броді Робертсон,

6

Це оригінальне запитання стосувалось Objective-C, але воно також було розміщене за кілька років до того, як був оголошений Свіфт. Отже, якщо ви приїжджаєте сюди від 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

щоб бути зрозумілим, це функція для цілих чисел у рядках.

ось невелика категорія помічників, заснована на відповіді Джона вище:

у .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

Відповідь Джона Келсбіка майже правильна, але опускає деякі випадки Edicode Edge .

Відповідно до документації дляdecimalDigitCharacterSet , цей набір включає всі символи, класифіковані Unicode як Nd. Таким чином, їхня відповідь, серед іншого, прийме:

  • (U + 0967 DEVANAGARI DIGIT ONE)
  • (U + 1811 МОНГОЛЬСЬКА ЦИФРА ОДНА)
  • 𝟙 (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]+$"];

1

Розширення відповіді @John Calsbeek та роз'яснення коментарів @Jeff та @gyratory circus .

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

0

Перевірте, чи рядок є числом, може бути корисним

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

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

0

Швидке розширення:

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

Для Свіфта 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

Простий написав розширення рядка:

extension String {
    var isNumeric: Bool {
        return self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.