How can I require that at least two lookahead patterns match within one regex?

懵懂的女人 提交于 2019-12-07 14:30:01

问题


The following regex ensures a password contains at least one lowercase, one uppercase, one number, and one special character:

^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[^a-zA-Z0-9\s]).*$

That works. Building on this, I'd like to require that only two of these groups be fulfilled in order for a password to be valid.

For example, these would be valid passwords: aaaaa5, BFEWREWRE77, #2ccc.

Is there I way I can modify this regex to support this requirement?


回答1:


You can do it like this:

with spaces forbidden:

^(?=([A-Z]+|[a-z]+|[0-9]+|[^a-zA-Z0-9\s]+))\1\S+$

with spaces allowed:

^\s*(?=((?:[A-Z]+\s*)+|(?:[a-z]+\s*)+|(?:[0-9]+\s*)+|(?:[^a-zA-Z0-9\s]+\s*)+))\1.+$

explanations:

(?=([A-Z]+|[a-z]+|[0-9]+|[^a-zA-Z0-9\s]+))\1 emulates the atomic group (?>[A-Z]+|[a-z]+|[0-9]+|[^a-zA-Z0-9\s]+). So once a branch of this group is matched, the regex engine is no more allowed to backtrack inside the matched characters.

Since the quantifiers are greedy by default, all the characters of one of the categories are matched by the atomic group.

The next character matched by \S or . is obviously from a different character class than the one used in the group.

Note: for the second pattern, since there is no limitation about the characters used in the string, you don't need to test the string until the end, so you can write:

^\s*(?=((?:[A-Z]+\s*)+|(?:[a-z]+\s*)+|(?:[0-9]+\s*)+|(?:[^a-zA-Z0-9\s]+\s*)+))\1.



回答2:


Since you asked for this long regex:

^(?:(?=.*[A-Z])(?=.*[a-z])|(?=.*[A-Z])(?=.*[0-9])|(?=.*[A-Z])(?=.*[^a-zA-Z0-9\s])|(?=.*[a-z])(?=.*[0-9])|(?=.*[a-z])(?=.*[^a-zA-Z0-9\s])|(?=.*[0-9])(?=.*[^a-zA-Z0-9\s])).+$

RegEx Demo




回答3:


Most modern engines offer conditionals.
This is a simple example pattern that inhibits re-entering the same group
and guarantees X out of Y requirements.

In essence, the groups are matched in no particular order based on only
the quantifier number X, which is the criteria that causes an alignment.

Its very scalable, just add a new group in the alternation.
Set X for how many unique groups you want to match.

This one is set for 3 out of the 4.
And just finish it off with any boundary requirements you have, like
^+regex_below+.*$.

Also, this consumes as it goes. It could easily be within a lookahead should there
be any length or other specific attributes.

Note that if the engine doesn't support conditionals (not all do), then this won't work.

 #  (?:.*?(?>((?(1)(?!))[a-z]+)|((?(2)(?!))[A-Z]+)|((?(3)(?!))[0-9]+)|((?(4)(?!))[^a-zA-Z0-9\s]+))){3}

 (?:
      .*?     
      (?>
           (                        # (1)
                (?(1) (?!) )
                [a-z]+ 
           )
        |  (                        # (2)
                (?(2) (?!) )
                [A-Z]+ 
           )
        |  (                        # (3)
                (?(3) (?!) )
                [0-9]+ 
           )
        |  (                        # (4)
                (?(4) (?!) )
                [^a-zA-Z0-9\s]+ 
           )
      )
 ){3}

Sample output when X is 4 (out of 4)

 **  Grp 0 -  ( pos 0 , len 11 ) 
B,B_+&*%#a0  
 **  Grp 1 -  ( pos 9 , len 1 ) 
a  
 **  Grp 2 -  ( pos 0 , len 1 ) 
B  
 **  Grp 3 -  ( pos 10 , len 1 ) 
0  
 **  Grp 4 -  ( pos 1 , len 1 ) 
,  



回答4:


you would have to do something like :

^(
    (?=1)(?=2)
    |
    (?=1)(?=3)
    |
    (?=1)(?=4)
    |
    (?=2)(?=3)
    |
    (?=2)(?=4)
    |
    (?=3)(?=4)
).*$

where 1,2,3 & 4 are your different patterns



来源:https://stackoverflow.com/questions/27110036/how-can-i-require-that-at-least-two-lookahead-patterns-match-within-one-regex

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!