29

I need to extract numbers from string and put them into a new array in Swift.

var str = "I have to buy 3 apples, 7 bananas, 10eggs"

I tried to loop each characters and I have no idea to compare between Characters and Int.

alphonse
  • 555
  • 1
  • 4
  • 10

9 Answers9

59

Swift 3/4

let string = "0kaksd020dk2kfj2123"
if let number = Int(string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()) {
    // Do something with this number
}

You can also make an extension like:

extension Int {
    static func parse(from string: String) -> Int? {
        return Int(string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined())
    }
}

And then later use it like:

if let number = Int.parse(from: "0kaksd020dk2kfj2123") { 
    // Do something with this number
} 
George Maisuradze
  • 1,654
  • 17
  • 16
38

First, we split the string so we can process the single items. Then we use NSCharacterSet to select the numbers only.

import Foundation

let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let strArr = str.split(separator: " ")

for item in strArr {
    let part = item.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()

    if let intVal = Int(part) {
        print("this is a number -> \(intVal)")
    }
}

Swift 4:

let string = "I have to buy 3 apples, 7 bananas, 10eggs"
let stringArray = string.components(separatedBy: CharacterSet.decimalDigits.inverted)
for item in stringArray {
    if let number = Int(item) {
        print("number: \(number)")
    }
}
Islam Q.
  • 3,343
  • 2
  • 26
  • 37
Vasil Garov
  • 4,473
  • 1
  • 22
  • 33
  • It's the easier and the better way to achive what you looking for. For simplify and look easy to use in your app, you can't create a extension of String class and create a method named `extractNumbers` – Vincent Saluzzo May 20 '15 at 08:35
  • 3
    In Swift 2, split does not longer works on Strings. see http://stackoverflow.com/a/30759312/2959462 – Jens Peter Oct 23 '15 at 08:37
10

Using the "regex helper function" from Swift extract regex matches:

func matchesForRegexInText(regex: String!, text: String!) -> [String] {

    let regex = NSRegularExpression(pattern: regex,
        options: nil, error: nil)!
    let nsString = text as NSString
    let results = regex.matchesInString(text,
        options: nil, range: NSMakeRange(0, nsString.length))
        as! [NSTextCheckingResult]
    return map(results) { nsString.substringWithRange($0.range)}
}

you can achieve that easily with

let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let numbersAsStrings = matchesForRegexInText("\\d+", str) // [String]
let numbersAsInts = numbersAsStrings.map { $0.toInt()! }  // [Int]

println(numbersAsInts) // [3, 7, 10]

The pattern "\d+" matches one or more decimal digit.


Of course the same can be done without the use of a helper function if you prefer that for whatever reason:

let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let regex = NSRegularExpression(pattern: "\\d+", options: nil, error: nil)!
let nsString = str as NSString
let results = regex.matchesInString(str, options: nil, range: NSMakeRange(0, nsString.length))
    as! [NSTextCheckingResult]
let numbers = map(results) { nsString.substringWithRange($0.range).toInt()! }
println(numbers) // [3, 7, 10]

Alternative solution without regular expressions:

let str = "I have to buy 3 apples, 7 bananas, 10eggs"

let digits = "0123456789"
let numbers = split(str, allowEmptySlices: false) { !contains(digits, $0) }
    .map { $0.toInt()! }
println(numbers) // [3, 7, 10]
Community
  • 1
  • 1
Martin R
  • 488,667
  • 78
  • 1,132
  • 1,248
10
let str = "Hello 1, World 62"
let intString = str.componentsSeparatedByCharactersInSet(
    NSCharacterSet
        .decimalDigitCharacterSet()
        .invertedSet)
    .joinWithSeparator("")

That will get you a string with all the number then you can just do this:

let int = Int(intString)

Just make sure you unwrap it since let int = Int(intString) is an optional.

Husein Kareem
  • 496
  • 1
  • 4
  • 12
5

Adapting from @flashadvanced's answer, I found that the following is shorter and simpler for me.

let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let component = str.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let list = component.filter({ $0 != "" }) // filter out all the empty strings in the component
print(list)

Tried in in the play ground and it works

Hope it helps :)

Community
  • 1
  • 1
steve0hh
  • 627
  • 6
  • 15
3

For me makes more sense to have it as a String extension, probably it's a matter of tastes:

func parseToInt() -> Int? {
    return Int(self.components(separatedBy: CharacterSet.decimalDigits.inverted).joined())
}

So can be used like this:

if let number = "0kaksd020dk2kfj2123".parseToInt() { 
// Do something with this number
} 
pegpeg
  • 1,049
  • 8
  • 10
2

Swift 2.2

  let strArr = str.characters.split{$0 == " "}.map(String.init)

        for item in strArr {
           let components = item.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)

                let part = components.joinWithSeparator("")

                    if let intVal = Int(part) {
                        print("this is a number -> \(intVal)")
                      }
              }
Alessandro Mattiuzzi
  • 1,871
  • 1
  • 15
  • 24
1
// This will only work with single digit numbers. Works with “10eggs” (no space between number and word
var str = "I have to buy 3 apples, 7 bananas, 10eggs"
var ints: [Int] = []
for char:Character in str {
  if let int = "\(char)".toInt(){
    ints.append(int)
  }
}

The trick here is that you can check if a string is an integer (but you can’t check if a character is). By looping though every character of the string, use string interpolation to create a string from the character and check if that string cas be casted as a integer.
If it can be, add it to the array.

// This will work with multi digit numbers. Does NOT work with “10 eggs” (has to have a space between number and word)
var str = "I have to buy 3 apples, 7 bananas, 10 eggs"
var ints: [Int] = []
var strArray = split(str) {$0 == " "}
for subString in strArray{
  if let int = subString.toInt(){
    ints.append(int)
  }
}

Here we split the string at any space and create an array of every substring that is in the long string.
We again check every string to see if it is (or can be casted as) an integer.

milo526
  • 4,631
  • 4
  • 38
  • 55
  • thanks a lot! but it recognizes 10 like 1 and 0 .how can i get number 10? – alphonse May 20 '15 at 07:26
  • Is there always a space between an integer and anything else? – milo526 May 20 '15 at 07:26
  • Is it possible to check, if after a number goes a number again (without space) , it recognizes as a one number?? – alphonse May 20 '15 at 07:44
  • It is but it really isn’t gonna be any easier or prettier than @flashadvanced answer (and you should probably mark his answer as “the” answer) – milo526 May 20 '15 at 07:47
0

Thanks for everyone who answered to my question.

I was looking for a block of code which uses only swift grammar, because I'm learning grammar only now..

I got an answer for my question.Maybe it is not an easier way to solve, but it uses only swift language.

var article = "I have to buy 3 apples, 7 bananas, 10 eggs"
var charArray = Array(article)

var unitValue = 0
var total = 0
for char in charArray.reverse() {

    if let number = "\(char)".toInt() {
        if unitValue==0 {
            unitValue = 1
        }
        else {
            unitValue *= 10
        }
        total += number*unitValue
    }
    else {
        unitValue = 0
    }
}
println("I bought \(total) apples.")
alphonse
  • 555
  • 1
  • 4
  • 10