0

I have been trying to implement a regex validation for a given city name.

My regex should match cities names like:

NY
San Francisco
München
København
Saint-Tropez
St. Lucia

So far I've searched the web for such-like regex but I've been having a hard time trying to implement it in swift.

this is the regex I've come up with, it seems to work in other languages but not in swift:

^[a-zA-Z\\u0080-\\u024F\\s\\/\\-\\)\(\`\.\"\']+$

Also as additional info, I'd like to implement it in the UITextField delegate method:

shouldChangeCharactersIn

something like this:

override func textField(_ textField: UITextField,
                            shouldChangeCharactersIn range: NSRange,
                            replacementString string: String) -> Bool {

        return validNameRegex.matches(string)
    }

using a NSRegularExpression Extension:

extension NSRegularExpression {

    convenience init(_ pattern: String) {
        do {
            try self.init(pattern: pattern)
        } catch {
            preconditionFailure("Illegal regular expression: \(pattern).")
        }
    }


    func matches(_ string: String) -> Bool {
        let range = NSRange(location: 0, length: string.utf16.count)
        return firstMatch(in: string, options: [], range: range) != nil
    }
}

Hope someone can help me out. Thanks in advance, and happy new year :)

  • 2
    What exactly is the regex validation going to be used for? Is the user inputting a city name and it validates it from a list via Regex? I feel like there are other ways to do this without Regex. – Dom Jan 08 '19 at 19:22
  • yeah i'll compare it to a list returned from the server. after the user enters it on the textfield – Mario Arámbula Jan 08 '19 at 19:32
  • try `^[a-zA-Z\\u0080-\\u024F\\s\\/\\-\\)\\(\\`\\.\\"\\']+$` – Leo Dabus Jan 08 '19 at 22:09
  • @MarioArámbula that sounds like you will be iterating through your entire list against another list of City names. It would be much better to use a Set. A Set generally has much faster run times than iterating list because it has unique values. So, if the user is entering a city name and you put it into a Set you could then see if your list from the server contains a value from your Set. That would be much faster and efficient than Regex. – Dom Jan 08 '19 at 22:20
  • Directly from the Swift documentation: `You use a set instead of an array when you need to test efficiently for membership and you aren’t concerned with the order of the elements in the collection, or when you need to ensure that each element appears only once in a collection.` – Dom Jan 08 '19 at 22:22
  • yeah the only big prob is that the server side has no unique ids for the city names. so for example NY, New York City, NYC. should be all valid, and since the user input is the one that is stored in the server the best way is just to make sure he inputs a valid name. (client doesnt want to implement a proper ISO list on the server and requested to do it in the UI side) :( – Mario Arámbula Jan 09 '19 at 06:49
  • Unless I misunderstand the regex, it looks to me like all you're doing is validating that you have one or more characters in a specific character set. Rather than a regex, why not form the inverse CharacterSet and then check that yourstring.rangeOfCharacter(from:options:range:) == nil – Feldur Jan 10 '19 at 00:39

1 Answers1

1

In the end I ended up using this regex:

^[a-zA-Z\u{0080}-\u{024F}\\s\\/\\-\\)\\(\\`\\.\\\"\\']*$

the main problem was scaping the "\" characters and the { } in the unicode