Reputation: 3802
I have read the Google python regex tutorial about regular expression and tried to test one of the patterns I need.
For example:
1a2b4a3c5b # is valid
1a5c4b4a3b # is not valid because of two 4s
So far I've tried:
pattern = r'([1-5])[abc]([1-5^\1])[abc]([1-5^\1\2])[abc]([1-5\1\2\3])[abc]([1-5\1\2\3\4])[abc]'
but it failed...
Upvotes: 2
Views: 1192
Reputation: 170257
You're trying to include a previous match in a negated character class, which is not possible.
The only way to do this is to do something like this:
^([1-5])[abc](?!\1)([1-5])[abc](?!\1|\2)([1-5])[abc](?!\1|\2|\3)([1-5])[abc](?!\1|\2|\3|\4)[1-5][abc]$
Needless to say, this is not something regex should be doing.
A demo:
#!/usr/bin/env python
import re
tests = ['1a2b4a3c5b', '1a5c4b4a3b']
pattern = re.compile(
r"""(?x) # enable inline comments and ignore literal spaces
^ # match the start of input
([1-5]) # match any of '1'..'5' and store it in group 1
[abc] # match 'a', 'b' or 'c'
(?!\1)([1-5]) # if the digit from group 1 is not ahead, match any of '1'..'5' and store it in group 2
[abc] # match 'a', 'b' or 'c'
(?!\1|\2)([1-5]) # if the digits from group 1 and 2 are not ahead, match any of '1'..'5' and store it in group 3
[abc] # match 'a', 'b' or 'c'
(?!\1|\2|\3)([1-5]) # if the digits from group 1, 2 and 3 are not ahead, match any of '1'..'5' and store it in group 4
[abc] # match 'a', 'b' or 'c'
(?!\1|\2|\3|\4)[1-5] # if the digits from group 1, 2, 3 and 4 are not ahead, match any of '1'..'5'
[abc] # match 'a', 'b' or 'c'
$ # match the end of input
""", re.X)
for t in tests:
if re.match(pattern, t):
print t
would print:
1a2b4a3c5b
Upvotes: 4
Reputation: 208565
I would suggest something like this instead of regex:
def matches(s):
return (len(s) == 10 and
set(s[::2]) == set('12345') and
set(s[1::2]) <= set('abc'))
>>> matches('1a2b4a3c5b')
True
>>> matches('1a5c4b4a3b')
False
Upvotes: 4
Reputation: 20297
You can use negative lookaheads to determine whether the next number is not one of the previous ones. The following regex should work:
pattern = r'^([1-5])[abc](?!\1)([1-5])[abc](?!\1|\2)([1-5])[abc](?!\1|\2|\3)([1-5])[abc](?!\1|\2|\3|\4)([1-5])[abc]$'
Edit: As Bart pointed out, the regex should start with ^
and end with $
to ensure it only matches exactly that string
Upvotes: 1