Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

find all numbers in a string with a NSScanner

I used the below code to extract numbers from inputString using NSScanner

NSString *inputString = @"Dhoni7 notout at183*runs in 145andhehit15four's and10sixers100";
NSString *numberString;
NSArray *elements = [inputString componentsSeparatedByString:@" "];
for (int i=0; i<[elements count];i++)
{
    NSScanner *scanner = [NSScanner scannerWithString:[elements objectAtIndex:i]];
    NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"1234567890"];

    // Throw away characters before the first number.
    [scanner scanUpToCharactersFromSet:numbers intoString:NULL];

    // Collect numbers.
    [scanner scanCharactersFromSet:numbers intoString:&numberString];

    // Result.
    int number = [numberString integerValue];
    if (number != 0)
    {
        NSLog(@"%d\n",number);
        numberString = nil;
    }
}

My expected output is 7 183 145 15 10 100

but the output I am getting is 7 183 145 10

It just extracts first occurrence of a number from each word. Eg: if its Dho7ni89 it just detects the 7 and doesn't detect 89. I would be really happy if someone helps me figure out a way to fix this.

like image 256
Manju Basha Avatar asked May 24 '15 15:05

Manju Basha


2 Answers

Matt was a little bit faster. Why do you split your string in the beginning?
A little code rearrangement will yield the desired result:

NSScanner *scanner = [NSScanner scannerWithString:@"Dhoni7 notout at183*runs in 145andhehit15four's and10sixers100"];
NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"1234567890"];

while (true) {
    // Throw away characters before a number
    [scanner scanUpToCharactersFromSet:numbers intoString:NULL];

    // Read the number
    NSString *numberString;
    if ([scanner scanCharactersFromSet:numbers intoString:&numberString]) {
        long number = [numberString integerValue];
        NSLog(@"%ld\n",number);
    } else {
        break;
    }
}

Outputting

7 183 145 15 10 100

NOTE
You could also use

NSCharacterSet *numbers = [NSCharacterSet decimalDigitCharacterSet];

to filter out the numbers. I find this a bit neater than listing the chars. It will however include, for example, the decimal digits of the Indic scripts and Arabic as well.

like image 101
luk2302 Avatar answered Oct 07 '22 11:10

luk2302


Your mistake is simple: you have started by making a false assumption. You artificially separate the string into words:

NSArray *elements = [inputString componentsSeparatedByString:@" "];
for (int i=0; i<[elements count];i++) {
    // scan for one number
}

Thus, that is exactly what happens. Each word is scanned for one number, once. If a word contains two numbers, the second number is never scanned - because that is not what you said to do.

The solution is to stop making that false assumption. Don't separate the string into words at all! Just keep repeating the process:

* scan up to a number
* scan the number

...until you reach the end of the scanner's string (isAtEnd).

like image 39
matt Avatar answered Oct 07 '22 11:10

matt