It should match all the following examples.
aBCd22
a2b2CD
22aBcD
It should match all the following examples.
aBCd22
a2b2CD
22aBcD
I don't know if you can do it with only one regular expression, but you can certainly do it with two. That said it seems a bit excessive to be using regex for this task.
In Perl, I would do:
m/\d.*\d/ # match exactly 2 numeric characters
&&
m/(?:[[:alpha:]].*){4}/ # match exactly 4 alpha characters
I don't think regex is the way to go here.
Sure, you could create an alternation of every possible allowed order of digits and letters, but you'd need 6 * 5 = 30 of them.
I don't know any way of doing the counting you want with regex.
You could have a regex to check you have 6 alpha-numeric characters, then do the counting manually.
Maybe this?
(?=[a-z]*\d?[a-z]*\d?)
(?![a-z]*\d[a-z]*\d[a-z]*\d)
(?=\d*[a-z]?\d*[a-z]?\d*[a-z]?\d*[a-z]?)
(?!\d*[a-z]\d*[a-z]\d*[a-z]\d*[a-z]\d*[a-z])
[\da-z]{2,6}
It works by making sure the selection has zero, one, or two digits (first lookahead), but doesn't have more than two (second lookahead). Similarly, it checks for zero to four letters (third lookahead) but not more than four (fourth lookahead). The fifth line matches one to six characters.
If you want to match words only, wrap it in \b
.
EDIT: Now you added a requirement for the length of the match to be six characters. Only a slight modification is needed:
(?=[a-z]*\d[a-z]*\d)
(?![a-z]*\d[a-z]*\d[a-z]*\d)
(?=\d*[a-z]\d*[a-z]\d*[a-z]\d*[a-z])
(?!\d*[a-z]\d*[a-z]\d*[a-z]\d*[a-z]\d*[a-z])
[\da-z]{6}
This regular expression should do it:
^(?=[a-zA-Z]*\d[a-zA-Z]*\d[a-zA-Z]*$)(?=\d*[a-zA-Z]\d*[a-zA-Z]\d*[a-zA-Z]\d*[a-zA-Z]\d*$).*
Or more compact:
^(?=[a-zA-Z]*(?:\d[a-zA-Z]*){2}$)(?=\d*(?:[a-zA-Z]\d*){4}$).*
A compact version, using the positive lookahead operator:
^(?=(.*[0-9]){2})(?=(.*[A-Za-z]){4})[A-Za-z0-9]{6}$
Explanation:
(?=(.*[0-9]){2}) # asserts that you have 2 digits
(?=(.*[A-Za-z]){4}) # asserts that you have 4 characters
[A-Za-z0-9]{6} # does the actual matching of exactly 6 alphanumeric characters
A simple test case, in Python:
import re
rex = re.compile('(?=(.*[0-9]){2})(?=(.*[A-Za-z]){4})[A-Za-z0-9]{6}')
tests = ['aBCd22', 'a2b2CD', '22aBcD', 'asd2as', '', '201ABC', 'abcA213']
for test in tests:
print "'%s' %s" %
(test, "matched" if rex.match(test) != None else "didn't match")
Output:
'aBCd22' matched
'a2b2CD' matched
'22aBcD' matched
'asdas' didn't match
'' didn't match
'201ABC' didn't match
'abcA213' didn't match
^((?<digit>\d)|(?<alpha>[a-zA-Z])){6}
(?<-alpha>){4}(?(alpha)(?!))
(?<-digit>){2}(?(digit)(?!))$
This will match 6 characters with exactly 2 digits and 4 letters. It does this by grabbing whatever it can then counting the results by popping them off the counter stack. Check this link for more details.