我有一些信用卡号,想根据以下规则验证它们。
► 只能由数字(0-9)组成
► 它可以有 4 个一组的数字,用一个连字符“-”分隔
► 它不能有 4 个或更多连续的重复数字
► 它可能只包含没有空格的数字
输入:
5123-4567-8912-3456
61234-567-8912-3456
4123356789123456
5133-3367-8912-3456
输出:
有效
无效(因为卡号没有分成4等份)
有效
无效(连续33个33位重复4次)
我已经尝试过 here,只有在末尾包含连字符时它才有效。有人可以给我一个正确的正则表达式吗。
编辑:
正则表达式代码:([0-9]{4}-){4}
要匹配的输入6244-5567-8912-3458
它不匹配,直到我在末尾加上连字符。
编辑
import re
import itertools
text="5133-3367-8912-3456"
print(len(text))
l=[(k, sum(1 for i in g)) for k,g in itertools.groupby(text)] #To calculate frequency of characters and later we can filter it with the condition v<=3 for checking the concurrency condition
if re.search(r'^[456]+',text) and len(text)==16 and re.search(r'[\d]',text) and all(v<=3 for k,v in l) and bool(re.search(r'\s',text)) is False and bool(re.search(r'[a-z]',text)) is False or( bool(re.search(r'-',text))is True and len(text)==19) :
print("it passed")
else :
print("False")
最佳答案
我的解决方案有两步逻辑。你不能一次性做到这一点的原因与 python 的限制有关。我们将保存它以备后用。如果您有兴趣,请查看附录 1。
2步:第一步检查'-'是否在正确的位置,第二步检查是否有4个连续相等的数字。
我将从第 2 步开始,这是最耗内存的步骤:检查是否没有连续的 4 个数字的正则表达式。以下正则表达式将执行:
((\d)(?!\2{3})){16}
解释:
( # group 1 start
(\d) # group 2: match a digit
(?!\2{3}) # negative lookahead: not 3 times group 2
){16} # repeat that 16 times.
第一步是匹配 4 位数字组,最终由“-”分隔(查看 example 2)这里要解决的问题是确保如果第一组和第二组数字由“-”分隔,那么所有组都需要用“-”分隔。我们设法通过在下一个正则表达式中使用对第 2 组的反向引用来做到这一点。
(\d{4})(-?)(\d{4})(\2\d{4}){2}
解释:
(\d{4}) # starting 4 digits
(-?) # group 2 contains a '-' or not
(\d{4}) # 2nd group of 4 digits
(\2\d{4}){2} # last 2 groups, starting with a backreference
# to group 2 ( a '-' or not)
示例程序:
import re
pattern1 = r"(\d{4})(-?)(\d{4})(\2\d{4}){2}"
pattern2 = r"((\d)(?!\2{3})){16}"
tests = ["5123-4567-8912-3456"]
for elt in tests:
if re.match( pattern1, elt):
print "example has dashes in correct place"
elt = elt.replace("-", "")
if re.match(pattern2, elt):
print "...and has the right numbers."
附录: 现在是沙漠。我把一个正则表达式放在一起一次性完成。让我们根据每个数字在组中的位置来考虑每个数字需要什么:
- 第一个数字:后跟 3 个数字
- 第二位数字:后接 3 位数字或数字、数字、破折号、数字
- 第 3 位数字:后跟 3 位数字或数字、破折号、数字、数字
- 第 4 位数字:后接 3 位数字或破折号、数字、数字、数字
因此,对于我们在示例 1 中使用的前瞻性,我们需要为每个数字呈现后续的所有可能性。让我们看一下一组 4 位数字的模式:
(
(\d) # the digit at hand
(?! # negative lookahead
\2{3} # digit, digit, digit
|\2{2}-\2 # OR digit, digit, dash, digit
|\2-\2{2} # OR digit, dash, digit, digit
|-\2{3} # OR dash, digit, digit, digit
)
){4} # 4 times, for each digit in a group of 4
当然,我们希望将其扩展到 16 位数字。我们需要定义是否可以在数字前添加“-”。一个简单的 -?
是行不通的,因为信用卡不是以破折号开头的。让我们使用交替:
(? # if
(?<=\d{4}) # lookbehind: there are 4 preceding digits
-? # then: '-' or not
| # else: nothing
)
结合起来,这使我们:
\b((?(?<=\d{4})-?|)(\d)(?!\2{3}|\2{2}-\2|\2-\2{2}|-\2{3})){16}\b
看看 example 3 。我们需要两边都有\b,因为我们想确保无论何时匹配成功,它都匹配 complete
字符串。
公平地说:如果这是要走的路,人们会怀疑。从好的方面来说,我们现在有一个分两步完成的正当理由:python 的标准 re 不支持条件等等。您可以通过使用替换来解决此问题。或者切换编程语言。 ;-)
附录 2: 人们问我 example 3 中的 16
来自哪里。完整的字符串不是可以有 19 个字符长吗?原因是只要内部正则表达式(第 1 组)匹配一次,它就会与 [0-9]
或 -[0-9]
匹配。该匹配必须恰好成功 16 次。
关于python - 使用正则表达式 python 验证卡号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46079770/