NSRegularExpression and understanding the syntax?

I'm working on text field validations specifically with regards to validating an email. I did research online and the most common solution seems to be to use the NSRegularExpression Class followed by using NSDataDetector. I've seen videos and examples on using regular expressions, but the code for it seems very confusing and the videos dont explain the actual code, rather just show it working... The most confusing part is this. If anyone could provide guidance on this topic that would be very, very helpful!


// QUESTIONS
// What is A-Z0-9a-z. etc....
// What is the {2, 3} at the end..
let emailRegEx = "[A-Z0-9a-z.-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,3}"


Thanks!

Accepted Reply

1. I've read what an NSPredicate is but I still dont understand exactly what it does

NSPredicate is a sort of Expression object and sort of a family member of NSExpression. Both classes implement an Expression Language which has its own syntax and semantics. NSPredicate returns boolean value, and NSExpression returns value of arbitrary types, when evaluated with a given object.


You may have read this aleady, but you should check this if you want to use NSPredicate or NSExpression in your app.

Predicate Programming Guide


Anyway, there are many articles about NSPredicate and you may have read some of them and still asks I still dont understand exactly what it does, that cannot be a good question as readers get no clue what's in your mind. Please try to explain what you understand and what you do not understand.


2. ... If I only use MATCHES, I get an error, what does the SELF mean here, is it similar to the way we use self.text = ....

You do not write something like `if == 0 { ... }` in your Swift code, no?

In Swift, `==` is a binary operator which claims operands on both hand sides.

Even when human readers can easily guess the left hand side, you need to specify it explicitly.


In the Expression Language used in NSPredicate or NSExpression, MATCHES is a binary operator and the left hand side operand is required.


I wrote NSPredicate returns boolean value when evaluated with a given object.

In your example code, when you use the predicate as `emailPredicate.evaluate(with: self.text)`, SELF represents `self.text`.


Your can write the same thing like this:

        let emailPredicate = NSPredicate(format:"text MATCHES %@", emailRegularExpression)
        
        if emailPredicate.evaluate(with: self) { //<- giving `self` instead of `self.text`
            //...
        } else {
            //...
        }

In this code, text in "text MATCHES %@" represents the `text` property of the given object `self`.



But I would not use NSPredicate as in your example. For example you can write something like this:

    func validateEmailTextField()  {
        let emailRegularExpression = "^[A-Z0-9a-z.-_]+@[A-Z0-9a-z-_.]+\\.[A-Za-z]{2,6}$" //^ and $ needed
        
        if
            let text = self.text,
            text.range(of: emailRegularExpression, options: .regularExpression) != nil
        {
            //...
        } else {
            //...
        }
    }

Or I would use NSRegularExpression explicitly.

Replies

What is A-Z0-9a-z. etc....


It's an abbreviation of character range inside [ and ].

A-Z represents ABCDEFGHIJKLMNOPQRSTUVWXYZ, a-z for abcdefghijklmnopqrstuvwxyz, and you see 0-9 is 0123456789.

So [A-Za-z] represents any single character of latin alphabets.


What is the {2, 3} at the end..


It is called as a quantifier and representing the number of repetition.

For example, [A-Za-z]{2,3} matches com, net, org, ***, jp, ae, in, us... Does not match info, name, or any strings of alphabets more than three characters or less than two characters.


Anyway, you should better search with "regular expression basics". Of course some of them are good, some of them are bad, and that depends on the reader. You need to find a good site for you.


And one more, almost all regex patterns on the internet cannot match all valid emails and may match some invalid emails.

For example, your regex pattern does not match: some.name@some-site.info, which should be a valid email.

And does match: .....@another-site.com, which would be invalid in almost all email hosts.

Thanks for clarifying that... so I learned a bit more about regular expressions and that makes sense. The small tutorial I watched used an NSPredicate and the evaluate method to validate the email as shown here. I made some modifications for my use case:


My question about NSPredicate are:

1. I've read what an NSPredicate is but I still dont understand exactly what it does

2. Based on my research, I use the MATCHES string comparison operator, however in the tutorial the developer added the SELF MATCHES.

If I only use MATCHES, I get an error, what does the SELF mean here, is it similar to the way we use self.text = ....



func validateEmailTextField()  {
      
      
      // Regular experession syntaxt (I understand this part)
      let emailRegularExpression = "[A-Z0-9a-z.-_]+@[A-Z0-9a-z-_.]+\\.[A-Za-z]{2,6}"
      
      
      // Predicate
      // Creating a predicate using NSPredicate that will be used to match a string from
      // the text field against our emailRegularExpression variable. SELF MATCHES? Documentation and
      // my research shows only MATCHES... what is the self referring to?
      let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailRegularExpression)
      
      // This part I get!
      if emailPredicate.evaluate(with: self.text) {
         
         
         // my own little method to update the text field rightview
         updateRightView(withIndicatorImage:  imageLiteral(resourceName: "Checkmark"))
         
      } else {
         
         // my own little method to update the text field rightview
         updateRightView(withIndicatorImage:  imageLiteral(resourceName: "Asterisk"))
         
      }
      
   }



Thanks!

1. I've read what an NSPredicate is but I still dont understand exactly what it does

NSPredicate is a sort of Expression object and sort of a family member of NSExpression. Both classes implement an Expression Language which has its own syntax and semantics. NSPredicate returns boolean value, and NSExpression returns value of arbitrary types, when evaluated with a given object.


You may have read this aleady, but you should check this if you want to use NSPredicate or NSExpression in your app.

Predicate Programming Guide


Anyway, there are many articles about NSPredicate and you may have read some of them and still asks I still dont understand exactly what it does, that cannot be a good question as readers get no clue what's in your mind. Please try to explain what you understand and what you do not understand.


2. ... If I only use MATCHES, I get an error, what does the SELF mean here, is it similar to the way we use self.text = ....

You do not write something like `if == 0 { ... }` in your Swift code, no?

In Swift, `==` is a binary operator which claims operands on both hand sides.

Even when human readers can easily guess the left hand side, you need to specify it explicitly.


In the Expression Language used in NSPredicate or NSExpression, MATCHES is a binary operator and the left hand side operand is required.


I wrote NSPredicate returns boolean value when evaluated with a given object.

In your example code, when you use the predicate as `emailPredicate.evaluate(with: self.text)`, SELF represents `self.text`.


Your can write the same thing like this:

        let emailPredicate = NSPredicate(format:"text MATCHES %@", emailRegularExpression)
        
        if emailPredicate.evaluate(with: self) { //<- giving `self` instead of `self.text`
            //...
        } else {
            //...
        }

In this code, text in "text MATCHES %@" represents the `text` property of the given object `self`.



But I would not use NSPredicate as in your example. For example you can write something like this:

    func validateEmailTextField()  {
        let emailRegularExpression = "^[A-Z0-9a-z.-_]+@[A-Z0-9a-z-_.]+\\.[A-Za-z]{2,6}$" //^ and $ needed
        
        if
            let text = self.text,
            text.range(of: emailRegularExpression, options: .regularExpression) != nil
        {
            //...
        } else {
            //...
        }
    }

Or I would use NSRegularExpression explicitly.

Thanks for clarifying!