[英]Selecting all Permutations Without Repetition using Regular Expressions in Python
我有三类字符,比如字母[A-Za-z]
、数字[0-9]
和符号[!@#$]
。 就论证而言,特定的符号并不重要。 我想在 Python 中使用正则表达式,以便我可以选择这三个类的所有排列,长度为 3,而无需重复。
例如,以下内容将成功匹配:
a1!
4B_
*x7
以下将失败:
ab!
BBB
*x_
a1!B
如果没有在正则表达式中明确写出类的每个潜在排列,我将如何处理?
我以前尝试过以下解决方案:
import re
regex = r"""
([A-Za-z]|[0-9]|[!@#$])
(?!\1) ([A-Za-z]|[0-9]|[!@#$])
(?![\1\2])([A-Za-z]|[0-9]|[!@#$])
"""
s = "ab1"
re.fullmatch(regex, s, re.VERBOSE)
但是字符串ab1
匹配不正确。 这是因为组引用\\1
和\\2
指的是组的实际匹配内容,而不是组中包含的正则表达式。
那么,如何引用包含在先前匹配组中的正则表达式,而不是它们的实际内容?
您的主要问题是您不能使用反向引用来否定模式的一部分,您只能使用它们来匹配/否定在相应捕获组中捕获的相同值。
注意[^\\1]
匹配除\\x01
字符之外的任何字符,而不是除 Group 1 所包含的字符之外的任何字符,因为在字符类中,反向引用不再如此。 ab1
匹配,因为b
不等于a
并且1
不等于a
和1
。
您可以使用的是一系列否定前瞻,它们会在某些条件下“排除”匹配,例如字符串不能有两个数字/字母/特殊字符。
rx = re.compile(r"""
(?!(?:[\W\d_]*[^\W\d_]){2}) # no two letters allowed
(?!(?:\D*\d){2}) # no two digits allowed
(?!(?:[^_!@\#$*]*[_!@\#$*]){2}) # no two special chars allowed
[\w!@\#$*]{3} # three allowed chars
""", re.ASCII | re.VERBOSE)
请参阅正则表达式演示。 在演示中,否定字符类被替换为.*
,因为测试是针对单个多行文本而不是单独的字符串执行的。
请参阅Python 演示:
import re
passes = ['a1!','4B_','*x7']
fails = ['ab!','BBB','*x_','a1!B']
rx = re.compile(r"""
(?!(?:[\W\d_]*[^\W\d_]){2}) # no two letters allowed
(?!(?:\D*\d){2}) # no two digits allowed
(?!(?:[^_!@\#$*]*[_!@\#$*]){2}) # no two special chars allowed
[\w!@\#$*]{3} # three allowed chars
""", re.ASCII | re.VERBOSE)
for s in passes:
print(s, ' should pass, result:', bool(rx.fullmatch(s)))
for s in fails:
print(s, ' should fail, reuslt:', bool(rx.fullmatch(s)))
输出:
a1! should pass, result: True
4B_ should pass, result: True
*x7 should pass, result: True
ab! should fail, reuslt: False
BBB should fail, reuslt: False
*x_ should fail, reuslt: False
a1!B should fail, reuslt: False
一个简单的解决方案是不要自己写出排列,而是让 Python 在itertools的帮助下完成。
from itertools import permutations
patterns = [
'[a-zA-Z]',
'[0-9]',
'[!@#$]'
]
regex = '|'.join(
''.join(p)
for p in permutations(patterns)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.