1

Consider following:

extension String {

    func isValidEmail() -> Bool {
        let characterset = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
         print(characterset)
        if self.rangeOfCharacter(from: characterset.inverted) != nil {
            return false
        }   else {
            return true
        }

    }
}

var name = "Login"
name.isValidEmail() // print true
var incorretLogin = "Loginъ"
incorretLogin.isValidEmail() // print false

Yes, function is work. But im in confussion - how its work? If i understand correct it work like that: it take set of characters, then check if all of tested string characters contain symbols from set, and if it is not, then it return false.

Ok, but what is inverted for? If i remove inverted, result will be wrong:

var name = "Login"
name.isValidEmail() // false
var incorretLogin = "Logъin"
incorretLogin.isValidEmail() // false

Now i understand nothing. If function check simply if string letters are from character set, then why is it matter if set inverted or not? Could someone explain?

I play a bit in playground:

 let characterset = CharacterSet(charactersIn: "a")
        print(characterset)
        print(characterset.inverted)

Print same result:

<CFCharacterSet Items(U+0061)>
<CFCharacterSet Items(U+0061)>
Evgeniy Kleban
  • 6,794
  • 13
  • 54
  • 107

2 Answers2

1

According to the documentation

rangeOfCharacter(from:)

Finds and returns the range in the receiver of the first character from a given character set.

The receiver is the string being checked. When no character from the set is found in the string, nil is returned.

When the set is inverted, it contains all invalid characters. Hence, rangeOfCharacter(from:) returns the location of the first invalid character. That is why your first approach works.

When you remove inverted, the call returns the location of the first valid character. Since "Logъin" has both valid and invalid characters, both calls return false. If you call your second function on a string consisting entirely of invalid characters, e.g. "Логин", you would get true.

Note that you can simplify the implementation by removing if:

let characterset = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
return self.rangeOfCharacter(from: characterset.inverted) == nil
Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

inverted "returns an inverted copy of the receiver." (see https://developer.apple.com/documentation/foundation/characterset).

In your case inverted means all the characters except the ones you provide in the initializer (all characters except letters and digits). So the method returns false if the email string contains any character that is not a letter or a digit.

Playground example: playground example

André Slotta
  • 13,774
  • 2
  • 22
  • 34
  • Please check my updated question. I check results for inverted and not, results the same, why? – Evgeniy Kleban Jan 28 '18 at 12:01
  • @EvgeniyKleban See my playground example. As you can see on the right they are different sets. While the "original" set contains the character **a** the inverted set does **not**. Instead it contains all characters **except** of the character **a**. – André Slotta Jan 28 '18 at 12:06