使用regex python

时间:2017-09-06 16:02:59

标签: python regex

我有一些信用卡号码,并希望通过以下规则对其进行验证。

►必须只包含数字(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")

4 个答案:

答案 0 :(得分:6)

我的解决方案有两步逻辑。你不能一气呵成的原因,与python的限制有关。我们将保存以供日后使用。如果您有兴趣,请查看附录1

2个步骤:第一步将检查&#39; - &#39;是在正确的地方,而第二个将检查是否有4个连续相等的数字。

我将从第二步开始,这是最耗费内存的一步:正则表达式,检查是否没有连续的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.

查看example 1

第一步是匹配4位数的组,最后用&#39; - &#39; (查看example 2)这里要解决的问题是确保如果第一和第二组数字由&#39; - &#39;分隔,那么所有组都需要用&分隔#39; - &#39 ;.我们设法通过在下一个正则表达式中使用对第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位数。我们需要定义是否可以添加&#39; - &#39;在数字之前。一个简单的-?不会做,因为信用卡并不是以破折号开头的。让我们使用交替:

(?                 # 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的标准版本不支持条件,什么不支持。您可以使用替换来解决此问题。或者切换编程语言。 ; - )

附录2:人们问我16来自example 3的位置。完整的字符串长度是19个字符是不是真的?原因是只要内部正则表达式(组1)匹配一次,它就与[0-9]-[0-9]匹配。这场比赛必须成功完成16次。

答案 1 :(得分:1)

你的正则表达式几乎是正确的。它要求四个短划线终止的数字组。你想要的是三个以字符串结尾的组,然后是一个非破折号终止的组,或一个没有破折号的blob:

(?:[0-9]{4}-){3}[0-9]{4}|[0-9]{16}

[Link]

由于您不需要捕获内容,因此我创建了组non-capturing。您也可以使用\d代替[0-9]

(?:\d{4}-?){3}\d{4}

[Link]

连续数字的验证可能更容易在单独的步骤中完成。一旦正则表达式匹配通过,删除所有破折号:

num = num.replace('-', '')

现在使用itertools.groupby检查重复的数字,例如question / answer

from itertools import groupby

if max(len(list(g)) for _, g in groupby(num)) >= 4:
    print('Invalid: too many repeated digits')

完整代码

from itertools import groupby
import re

pattern = re.compile(r'(?:\d{4}-){3}\d{4}|\d{16}')

def count_consecutive(num):
    return max(len(list(g)) for _, g in groupby(num)

num = '6244-5567-8912-3458'
if not pattern.fullmatch(num) or count_consecutive(num.replace('-', '')) >= 4:
    print('Failed')
else:
   print('Success')

答案 2 :(得分:1)

除非你真的想要/需要使用 regex ,否则这个任务可以通过这样简单的python代码来解决:

import itertools
card = "5133-3467-8912-.456"

# Check if hyphens are ok
if (len(card.split('-')) == 1 and len(card) == 16) or (len(card.split('-')) == 4 and all(len(i) == 4 for i in card.split("-"))):
    # Remove all hyphens (if any)
    card = card.replace("-", "")
    try:
        # Check if numbers only
        int(card)
        # Check if more than 3 repeated digits
        if max(len(list(g)) for _, g in itertools.groupby(card)) > 3:
            print("Failed: 4+ repeated digits")
        else:
            print("Passed")
    except ValueError as e:
        print("Failed: non-digit characters")
else:
    print("Failed: bad hyphens or length")

答案 3 :(得分:0)

问题陈述:

  1. 它必须以4,5或6开头
  2. 它必须精确地包含16位数字//删除连字符并计算长度
  3. 它只能由数字(0-9)组成
  4. 它可能是4位一组的数字,中间用一个连字符“-”

正则表达式:

^(4|5|6)[1-9]{3}-?[1-9]{4}-?[1-9]{4}-?[1-9]{4}$ 
  • 不得使用任何字母(不得包含非数字数据)

正则表达式:

[a-zA-z]
  • 它不能包含4个或更多连续的重复数字

正则表达式:

(\d)\1{3,}

完整代码:

import re

new_cc=str(input())
#### to check the total lengt
without_hyp=new_cc.replace("-","")
###check for starting with 4,5 or 6 and {1234}: 4 digits within each group
match=re.search(r"^(4|5|6)[1-9]{3}-?[1-9]{4}-?[1-9]{4}-?[1-9]{4}$",str(new_cc))
### check for alphabet characters
nomatch=re.search(r"[a-zA-z]",str(new_cc))
##check for repetative numbers
con=re.search(r"(\d)\1{3,}",str(without_hyp))

if nomatch == None:
        if match != None:
                if len(new_cc.replace("-","")) == 16:
                        if match.group(0):
                                if con == None:
                                        print('Valid')
                                else:
                                        print('Invalid')
                        else:
                                print('Invalid')
                else:
                        print('Invalid')
        else:
                print('Invalid')
else:
        print('Invalid')