Search code examples
regexswiftfilterswift3nsregularexpression

Swift: Finding an Object Property via regex


Target: The following function shall iterate over an array of objects and check a specific property of all objects. This property is a string and shall be matched with a user input via regex. If there's a match the object shall be added to an array which will further be passed to another function.

Problem: I don't know how to set up regex in Swift 3. I'm rather new in Swift at all, so an easily understandable solution would be very helpful :)

How it currently looks like:

    func searchItems() -> [Item] {
        var matches: [Item] = []
        if let input = readLine() {
            for item in Storage.storage.items {    //items is a list of objects
                if let query = //regex with query and item.name goes here {
                    matches.append(item)
                }
            }
            return matches
        } else {
            print("Please type in what you're looking for.")
            return searchItems()
        }
    }

This is what Item looks like (snippet):

    class Item: CustomStringConvertible {

        var name: String = ""
        var amount: Int = 0
        var price: Float = 0.00
        var tags: [String] = []
        var description: String {
            if self.amount > 0 {
                return "\(self.name) (\(self.amount) pcs. in storage) - \(price) €"
            } else {
                return "\(self.name) (SOLD OUT!!!) - \(price) €"
            }
        }

        init(name: String, price: Float, amount: Int = 0) {
            self.name = name
            self.price = price
           self.amount = amount
        }
    }

    extension Item: Equatable {

        static func ==(lhs: Item, rhs: Item) -> Bool {
            return lhs.name == rhs.name
        }

    }

Solved. I just edited this post to get a badge :D


Solution

  • For the purpose of letting the answer to be generic and clear, I will assume that the Item model is:

    struct Item {
        var email = ""
    }
    

    Consider that the output should be a filtered array of items that contains items with only valid email.

    For such a functionality, you should use NSRegularExpression:

    The NSRegularExpression class is used to represent and apply regular expressions to Unicode strings. An instance of this class is an immutable representation of a compiled regular expression pattern and various option flags.

    According to the following function:

    func isMatches(_ regex: String, _ string: String) -> Bool {
        do {
            let regex = try NSRegularExpression(pattern: regex)
    
            let matches = regex.matches(in: string, range: NSRange(location: 0, length: string.characters.count))
            return matches.count != 0
        } catch {
            print("Something went wrong! Error: \(error.localizedDescription)")
        }
    
        return false
    }
    

    You can decide if the given string does matches the given regex.

    Back to the example, consider that you have the following array of Item Model:

    let items = [Item(email: "invalid email"),
                 Item(email: "[email protected]"),
                 Item(email: "Hello!"),
                 Item(email: "[email protected]")]
    

    You can get the filtered array by using filter(_:) method:

    Returns an array containing, in order, the elements of the sequence that satisfy the given predicate.

    as follows:

    let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
    
    let emailItems = items.filter {
        isMatches(emailRegex, $0.email)
    }
    
    print(emailItems) // [Item(email: "[email protected]"), Item(email: "[email protected]")]
    

    Hope this helped.