Как проверить, содержит ли NSString числовое значение?

У меня есть строка, которая генерируется из формулы, однако я хочу использовать эту строку только до тех пор, пока все ее символы являются числовыми, если не то, что я хочу сделать что-то другое, например, отобразить сообщение об ошибке.

Я огляделся, но мне трудно найти что-то, что работает в соответствии с тем, что я хочу сделать. Я просмотрел NSScanner, но я не уверен, что он проверяет всю строку, а затем я не совсем уверен, как проверить, являются ли эти символы числовыми.

- (void)isNumeric:(NSString *)code{

    NSScanner *ns = [NSScanner scannerWithString:code];
    if ( [ns scanFloat:NULL] ) //what can I use instead of NULL?
    {
        NSLog(@"INSIDE IF");
    }
    else {
    NSLog(@"OUTSIDE IF");
    }
}

Итак, после еще нескольких часов поиска я наткнулся на реализацию, которая соответствует именно тому, что я ищу.

поэтому, если вы хотите проверить, есть ли в вашем NSString какие-либо буквенно-цифровые символы, это работает здесь

-(bool) isNumeric:(NSString*) hexText
{

    NSNumberFormatter* numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];

    NSNumber* number = [numberFormatter numberFromString:hexText];

    if (number != nil) {
        NSLog(@"%@ is numeric", hexText);
        //do some stuff here      
        return true;
    }

    NSLog(@"%@ is not numeric", hexText);
    //or do some more stuff here
    return false;
}

надеюсь это поможет.


person C.Johns    schedule 10.07.2011    source источник
comment
Если кому-то интересно, я создал список с некоторыми решениями, представленными здесь, в категории NSString — NSString+isNumeric   -  person bejonbee    schedule 15.02.2013


Ответы (7)


Что-то вроде этого будет работать:

@interface NSString (usefull_stuff)
- (BOOL) isAllDigits;
@end

@implementation NSString (usefull_stuff)

- (BOOL) isAllDigits
{
    NSCharacterSet* nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
    NSRange r = [self rangeOfCharacterFromSet: nonNumbers];
    return r.location == NSNotFound && self.length > 0;
}

@end

тогда просто используйте его так:

NSString* hasOtherStuff = @"234 other stuff";
NSString* digitsOnly = @"123345999996665003030303030";

BOOL b1 = [hasOtherStuff isAllDigits];
BOOL b2 = [digitsOnly isAllDigits];

Вам не нужно оборачивать функциональность в расширение частной категории, как это, но это, несомненно, упрощает повторное использование.

Мне это решение нравится больше, чем другие, так как оно никогда не переполнит некоторое число int/float, сканируемое с помощью NSScanner — количество цифр может быть практически любой длины.

person TomSwift    schedule 09.12.2011
comment
Я думаю, что эта идея великолепна. Это мне очень помогло. - person puchikon; 10.01.2012
comment
В этом подходе проблема возникает, когда строка = @ (пустая строка). Это явно не цифра, но возвращает YES. - person Neru; 24.09.2014
comment
@Neru Я думаю, вы могли бы поместить это в оператор if, который сначала проверяет, является ли строка пустой, с помощью string.length? - person Supertecnoboff; 12.05.2016

Рассмотрим NSString integerValue - он возвращает NSInteger . Однако он будет принимать некоторые строки, которые не являются полностью числовыми, и не предоставляет механизма для определения строк, которые вообще не являются числовыми. Это может быть или не быть приемлемым.

Например, " 13 " -> 13, "42foo" -> 42 и "helloworld" -> 0.

Удачного кодирования.


Теперь, поскольку приведенное выше было своего рода касанием к вопросу, см. определение, является ли строка числовой. Код взят из ссылки с добавленными комментариями:

BOOL isNumeric(NSString *s)
{
   NSScanner *sc = [NSScanner scannerWithString: s];
   // We can pass NULL because we don't actually need the value to test
   // for if the string is numeric. This is allowable.
   if ( [sc scanFloat:NULL] )
   {
      // Ensure nothing left in scanner so that "42foo" is not accepted.
      // ("42" would be consumed by scanFloat above leaving "foo".)
      return [sc isAtEnd];
   }
   // Couldn't even scan a float :(
   return NO;
}

Вышеприведенное работает только с scanFloat -- например. нет scanInt -- потому что диапазон числа с плавающей запятой намного больше, чем диапазон целого числа (даже 64-битного целого числа).

Эта функция проверяет «полностью числовое» значение и примет "42" и "0.13E2", но отклонит " 13 ", "42foo" и "helloworld".

person Community    schedule 10.07.2011
comment
Если у меня есть NSString в другом методе, который я хочу передать этому логическому методу, как мне это сделать? Я привык просто передавать переменные следующим образом: [self methodname:valuetopass]; - person C.Johns; 11.07.2011
comment
Ну, это похоже... [objWhichHasMethod isNumber: &theNSStringToPass] & получает указатель на theNSStringToPass (где я предполагаю, что theNSStringToPass имеет тип NSString). - person ; 11.07.2011
comment
@C.Johns Однако во многих случаях я ожидаю, что переменная, которая будет передана уже, будет иметь тип NSString* и не иметь ее как таковой ... звучит подозрительно. - person ; 11.07.2011
comment
Предупреждение: похоже, это не работает с числами с десятичным разделителем, кроме точки. В некоторых языках разделителем является запятая. - person mrmuggles; 14.12.2013
comment
@mrmuggles: используйте +localizedScannerWithString: для создания локализованного экземпляра сканера (в качестве альтернативы вызовите -setLocale: для экземпляра сканера). Отличный ответ, кстати. - person david a.; 24.06.2014

Это очень просто.

+ (BOOL)isStringNumeric:(NSString *)text
{
    NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
    NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:text];        
    return [alphaNums isSupersetOfSet:inStringSet];
}
person arturdev    schedule 08.07.2014
comment
Будет ли это работать и для отрицательных чисел? то есть: -17,2467 - person Supertecnoboff; 12.05.2016

Нравится:

- (void)isNumeric:(NSString *)code{

    NSScanner *ns = [NSScanner scannerWithString:code];
    float the_value;
    if ( [ns scanFloat:&the_value] )
    {
        NSLog(@"INSIDE IF");
        // do something with `the_value` if you like
    }
    else {
    NSLog(@"OUTSIDE IF");
    }
}
person Matt Connolly    schedule 10.07.2011
comment
Только для проверки, когда отсканированное значение не требуется, достаточно ли NULL или должен быть передан действительный адрес? (Ссылка указывает, что NULL здесь ОКЕЙ.) - person ; 11.07.2011
comment
@WrightsCS NSString содержит текст. Текст может представлять NSInteger, но сам текст — это просто данные. В этом случае просто используйте другой scanXYZ для чтения текстового представления в соответствующую переменную. Обратите внимание, что scanInt принимает int*, а не NSInteger. - person ; 11.07.2011
comment
@pst Да, но это может показаться излишним, если вам нужно проверить наличие NSInteger; вам понадобится новый метод isNumeric:. - person WrightsCS; 11.07.2011
comment
Если вы не согласны с тем, что целые числа будут сканироваться как числа с плавающей запятой. то есть: scanFloat будет работать как с целыми числами, так и с числами с плавающей запятой. - person Matt Connolly; 11.07.2011

Столкнулся с той же проблемой в Swift.
В Swift вы должны использовать этот код, согласно ответу TomSwift:

func isAllDigits(str: String) -> Bool {

    let nonNumbers = NSCharacterSet.decimalDigitCharacterSet()

    if let range = str.rangeOfCharacterFromSet(nonNumbers) {
        return true
    }
    else {
        return false
    }
}

P.S. Также вы можете использовать другие NSCharacterSets или их комбинации для проверки вашей строки!

person Alexander Larionov    schedule 05.11.2014

Для простых чисел, таких как «12234» или «231231,23123», ответ может быть простым.

Для целых чисел существует закон преобразования: когда строка с целым числом преобразуется в целое (или длинное) число, а затем снова преобразуется обратно в другую строку, эти строки будут равны.

В Objective C это будет выглядеть так:

NSString *numStr=@"1234",*num2Str=nil;
num2Str=[NSString stringWithFormat:@"%lld",numStr.longlongValue];

if([numStr isEqualToString: num2Str]) NSLog(@"numStr is an integer number!");

Используя этот закон преобразования, мы можем создать решение
для обнаружения double или long чисел:

NSString *numStr=@"12134.343"
NSArray *numList=[numStr componentsSeparatedByString:@"."];

if([[NSString stringWithFormat:@"%lld", numStr.longLongValue] isEqualToString:numStr]) NSLog(@"numStr is an integer number"); 
else 
if( numList.count==2 &&
               [[NSString stringWithFormat:@"%lld",((NSString*)numList[0]).longLongValue] isEqualToString:(NSString*)numList[0]] &&
               [[NSString stringWithFormat:@"%lld",((NSString*)numList[1]).longLongValue] isEqualToString:(NSString*)numList[1]] )
            NSLog(@"numStr is a double number");
else 
NSLog(@"numStr is not a number");

Я не копировал приведенный выше код из своего рабочего кода, поэтому могут быть некоторые ошибки, но я думаю, что основная мысль ясна. Конечно, это решение не работает с числами типа "1E100", а также не учитывает размер целой и дробной частей. Используя закон, описанный выше, вы можете делать любое обнаружение чисел, которое вам нужно.

person sinoptic    schedule 08.07.2014

Ответ К.Джонса неверен. Если вы используете средство форматирования, вы рискуете, что Apple в какой-то момент изменит свою кодовую базу, и средство форматирования выдаст частичный результат. Ответ Тома тоже неверен. Если вы используете метод rangeOfCharacterFromSet и проверяете NSNotFound, он зарегистрирует значение true, если строка содержит хотя бы одно число. Точно так же другие ответы в этой теме предлагают использовать метод целочисленного значения. Это также неправильно, потому что он зарегистрирует истину, если в строке присутствует хотя бы одно целое число. ОП запросил ответ, который гарантирует, что вся строка является числовой. Попробуй это:

NSCharacterSet *searchSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];

Том был прав насчет этой части. Этот шаг дает вам нечисловые строковые символы. Но тогда делаем так:

NSString *trimmedString = [string stringByTrimmingCharactersInSet:searchSet];

return (string.length == trimmedString.length);

Перевернутый набор символов Тома может ОБРЕЗАТЬ строку. Таким образом, мы можем использовать этот метод обрезки, чтобы проверить, существуют ли в строке какие-либо нечисловые значения, сравнив их длины.

person Scott Yelvington    schedule 27.01.2018