0

I have a password match requirment where I do not want to include German umlaut in password validation. Current match criteria is:

  1. one lower case
  2. one upper case
  3. One digit
  4. minimum 10 chars

I created a regex as below:

func matchPasswordWith(_ text: String) -> Bool {
    let predicate = NSPredicate(format: "SELF MATCHES %@","^(?=.*?[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{10,}$")
    return predicate.evaluate(with: text)
}

But when a user enters any umlaut (e.g. ü, ä, Ä, ß), the above regex returns true but I want to exclude umlaut match.

Please suggest what am I doing wrong here.

HangarRash
  • 7,314
  • 5
  • 5
  • 32
Gagan_iOS
  • 3,638
  • 3
  • 32
  • 51
  • 2
    `.{10,}` matches ANY ten or more chars. You must come up with another requirement: which characters do you allow? If any of those mentioned before, just put them into a character class - `[0-9a-zA-Z]{10,}`, The `(?=.*[a-zA-Z])` lookahead is redundant since you already have `(?=.*[a-z])(?=.*[A-Z])`. And you do not need `^` and `$` as `MATCHES` requires a full string match (although I'd still use the explicit anchors). – Wiktor Stribiżew Jun 15 '23 at 13:31
  • 1
    I'll second the need to specify the exact list of characters you do want to accept. What about emoji characters? What about Cyrillic? Japanese? Letters with other diacritics besides umlauts? Basic punctuation like period, comma, percent sign, etc.? Right now your expression says "allow any character but ensure there is at least one uppercase letter, at least one lowercase letter, and at least one digit, with a total length of 10 or more. – HangarRash Jun 15 '23 at 17:03
  • Just add the umlats to a class, then put it inline with the other assertions `^(?!.*[üäÄß])(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{10,}$` its the validation chain. I would limit the max characters to something less than 40mb or so. – sln Jun 15 '23 at 21:43
  • Try something like [`^(?=\D*\d)(?=[^a-z]*[a-z])(?=[^A-Z]*[A-Z])[^äöüÄÖÜß]{10,}$`](https://regex101.com/r/CFuwCQ/1) – bobble bubble Jun 16 '23 at 08:36

2 Answers2

1

You can negate values from a character class, using a character class intersection.

The syntax is &&[], and must be placed within the character class, at the end.

Additionally, you can reduce your pattern.

(?i)^[a-z\d&&[^äöüÄÖÜß]]{10,}$

The (?i) will toggle-on case-insensitive mode.

Here are some examples.

These will match.

abcdefghij
1234567890
AbCdE12345

And, these will not.

äbcdefghij
12345
ÄbCdE12345
Reilas
  • 3,297
  • 2
  • 4
  • 17
0

You could exclude umlauts in your password matching by including all the non-umlaut characters you want to have. Replacing (?=.*[a-zA-Z]).{10,}$ with something like [A-Za-z0-9]{10,}$

func matchPasswordWith(_ text: String) -> Bool {
    let predicate = NSPredicate(format: "SELF MATCHES %@","^(?=.*?[0-9])(?=.*[a-z])(?=.*[A-Z])[A-Za-z0-9]{10,}$")
    return predicate.evaluate(with: text)
}

[A-Za-z0-9]{10,} Checks that all characters are either a letter or a number and that there are at least 10 characters. Obviously it also excludes other special characters, but you could always add those to your character set like: [A-Za-z0-9@#$%^&*]{10,}. or whatever other characters you want to include.

David Greydanus
  • 2,551
  • 1
  • 23
  • 42
  • There is a lot of non-umlat characters. Should he put them all in a class, over 1 million of them ? It really annoys me when companies limit my password to a small list of characters and a small amount. I certainly don't do business with them. – sln Jun 15 '23 at 23:11