40

I have a string that contains words as well as a number. How can I extract that number from the string?

NSString *str = @"This is my string. #1234";

I would like to be able to strip out 1234 as an int. The string will have different numbers and words each time I search it.

Ideas?

Nic Hubbard
  • 41,587
  • 63
  • 251
  • 412
  • Have a look at a [previously posted answer](http://stackoverflow.com/questions/1138759/convert-first-number-in-an-nsstring-into-an-integer) here. – Bringo Jan 11 '11 at 22:50

7 Answers7

106

Here's an NSScanner based solution:

// Input
NSString *originalString = @"This is my string. #1234";

// Intermediate
NSString *numberString;

NSScanner *scanner = [NSScanner scannerWithString:originalString];
NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];

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

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

// Result.
int number = [numberString integerValue];

(Some of the many) assumptions made here:

  • Number digits are 0-9, no sign, no decimal point, no thousand separators, etc. You could add sign characters to the NSCharacterSet if needed.
  • There are no digits elsewhere in the string, or if there are they are after the number you want to extract.
  • The number won't overflow int.

Alternatively you could scan direct to the int:

[scanner scanUpToCharactersFromSet:numbers intoString:NULL];
int number;
[scanner scanInt:&number];

If the # marks the start of the number in the string, you could find it by means of:

[scanner scanUpToString:@"#" intoString:NULL];
[scanner setScanLocation:[scanner scanLocation] + 1];
// Now scan for int as before.
martin clayton
  • 76,436
  • 32
  • 213
  • 198
57

Self contained solution:

+ (NSString *)extractNumberFromText:(NSString *)text
{
  NSCharacterSet *nonDigitCharacterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
  return [[text componentsSeparatedByCharactersInSet:nonDigitCharacterSet] componentsJoinedByString:@""];
}

Handles the following cases:

  • @"1234" → @"1234"
  • @"001234" → @"001234"
  • @"leading text get removed 001234" → @"001234"
  • @"001234 trailing text gets removed" → @"001234"
  • @"a0b0c1d2e3f4" → @"001234"

Hope this helps!

Zorayr
  • 23,770
  • 8
  • 136
  • 129
5

You could use the NSRegularExpression class, available since iOS SDK 4.

Bellow a simple code to extract integer numbers ("\d+" regex pattern) :

- (NSArray*) getIntNumbersFromString: (NSString*) string {

  NSMutableArray* numberArray = [NSMutableArray new];

  NSString* regexPattern = @"\\d+";
  NSRegularExpression* regex = [[NSRegularExpression alloc] initWithPattern:regexPattern options:0 error:nil];

  NSArray* matches = [regex matchesInString:string options:0 range:NSMakeRange(0, string.length)];
  for( NSTextCheckingResult* match in matches) {
      NSString* strNumber = [string substringWithRange:match.range];
      [numberArray addObject:[NSNumber numberWithInt:strNumber.intValue]];
  }

  return numberArray; 
}
Farlei Heinen
  • 5,859
  • 1
  • 21
  • 19
  • Regular Expression is powerful. But in this simple case, I think @Zorayr 's answer is the best. – Yi Jiang May 19 '15 at 01:54
  • Regardless of my answer, I think using regex here might be an overkill and a bit more of a maintenance hazard; no one really understands regex and it's hard to debug. – Zorayr May 19 '15 at 02:13
  • @Zorayr : I agree that it maybe is a little overkill, but I don't think it's a maintenance hazard. Actually it's really easy to add new functionality and a developer can reuse the pattern in any language that accepts regex. – Farlei Heinen May 20 '15 at 03:39
  • I add an example to make my answer more clear. It work for integer values. To expand to float values use this pattern: @"[\\d[.]]+" – Farlei Heinen May 20 '15 at 03:41
  • Very nice. Don't fear the regex. – Marcus Adams Mar 27 '18 at 12:54
3

Try this answer from Stack Overflow for a nice piece of C code that will do the trick:

for (int i=0; i<[str length]; i++) {
        if (isdigit([str characterAtIndex:i])) {
                [strippedString appendFormat:@"%c",[str characterAtIndex:i]];
        }
}
Community
  • 1
  • 1
Sam Ritchie
  • 10,988
  • 4
  • 42
  • 53
  • I wouldn't recommend using a c-style for loop here; this could cause a significant lag on larger strings, especially if executed on the main thread. – Zorayr May 19 '15 at 02:11
1

By far the best solution! I think regexp would be better, but i kind of sux at it ;-) this filters ALL numbers and concats them together, making a new string. If you want to split multiple numbers change it a bit. And remember that when you use this inside a big loop it costs performance!

    NSString *str= @"bla bla bla #123 bla bla 789";
    NSMutableString *newStr = [[NSMutableString alloc] init];;
    int j = [str length];
    for (int i=0; i<j; i++) {       
        if ([str characterAtIndex:i] >=48 && [str characterAtIndex:i] <=59) {
            [newStr appendFormat:@"%c",[str characterAtIndex:i]];
        }               
    }

    NSLog(@"%@  as int:%i", newStr, [newStr intValue]);
Roger
  • 7,535
  • 5
  • 41
  • 63
0

Swift extension for getting number from string

extension NSString {

func getNumFromString() -> String? {

    var numberString: NSString?
    let thisScanner = NSScanner(string: self as String)
    let numbers = NSCharacterSet(charactersInString: "0123456789")
    thisScanner.scanUpToCharactersFromSet(numbers, intoString: nil)
    thisScanner.scanCharactersFromSet(numbers, intoString: &numberString)
    return numberString as? String;
}
}
Petro Korienev
  • 4,007
  • 6
  • 34
  • 43
-1

NSPredicate is the Cocoa class for parsing string using ICU regular expression.

Daniel Farrell
  • 9,316
  • 8
  • 39
  • 62