Python正则表达式可检测字符串后的多个可选子字符串之一

时间:2018-10-22 18:16:06

标签: python regex

我需要匹配以下模式:AAXX#

位置:
* AA来自1-3个char字母前缀的集合(即list),
* XX来自不同的预定义字符串列表,并且
* any single-digit numeral之后。

AA字符串:['bo','h','fr','sam','pe']

XX个字符串:cl + ['x','n','r','nr','eaner] //否则,// ro

所需结果:bool指示是否有任何可能的连击与提供的字符串匹配。

示例测试字符串:
item = "boro1"-即bo + ro + 1
item = "samcl2"-即sam + cl + 2
item = "hcln3"-即h + cln + 3

我能想到的最好的方法是使用一个循环,但是我在使用必需的正则表达式时遇到了麻烦。它适用于单字母可选cln, clx, clr,但不适用于较长字母的clnr, cleaner

代码:

item = "hclnr2" #h + clnr + 2
out = False
arr = ['bo','h','fr','sam','pe']
for mnrl in arr:
    myrx = re.escape(mnrl) + r'cl[x|n|r|nr|eaner]\d'
    thisone = bool(re.search(myrx, item))
    print('mnrl: '+mnrl+' - ', thisone)
    if thisone: out = True

##########################################################################
# SKIP THIS - INCLUDED IN CASE S/O HAS A BETTER SOLUTION THAN A SECOND LOOP
# THE ABOVE FOR-LOOP handled THE CL[opts] TESTS, THIS LOOP DOES THE RO TESTS
##########################################################################
#if not out: #If not found a match amongst the "cl__" options, test for "ro"
#    for mnrl in arr:
#        myrx = re.escape(mnrl) + r'ro\d'
#        thisone = bool(re.search(myrx, item))
#        print('mnrl: '+mnrl+' - ', thisone)
#    if thisone: out = True
##########################################################################

print('result: ', out)

打印:

mnrl: bo - False
mnrl: h - False <======
mnrl: fr - False
mnrl: sam - False
mnrl: pe - False

但是,将item更改为:

item = "hcln2" #h + cln + 2

打印:
mnrl: bo - False
mnrl: h - True <========
mnrl: fr - False
mnrl: sam - False
mnrl: pe - False

item = hclr5item = hclx9的同上,但不是hcleaner9

2 个答案:

答案 0 :(得分:2)

我的方法是

import re

words = ['boro1', 'samcl2', 'hcln3', 'boro1+unwantedstuff']

p = r'(bo|h|fr|sam|pe)(cl(x|n|r|nr|eaner|)|ro)\d$'

for w in words:
      print(re.match(p, w))

结果:

<_sre.SRE_Match object; span=(0, 5), match='boro1'>
<_sre.SRE_Match object; span=(0, 6), match='samcl2'>    
<_sre.SRE_Match object; span=(0, 5), match='hcln3'>
None

对于所需的布尔输出,您只需将match对象转换为'bool'。

答案 1 :(得分:2)

您的代码中有些误解包括字符类的使用(语法:[ ... ])。当您使用字符类时,字符类中的任何单个字符都将尝试匹配字符串(使用其他一些字符的情况除外,这些字符在特定位置时分别为^-职位)。这意味着:

[x|n|r|nr|eaner]

将匹配x,|,n,r,e,a中的任何一个字符(重复的字符实际上将被丢弃)

我不确定您为什么要在代码中执行诸如re.escape之类的所有复杂操作,我相信您可以理解以下代码片段以使其适应您的情况:

import re

def matchPattern(item, extract=False):
    result = re.match(r"(bo|h|fr|sam|pe)((?:cl(?:nr|eaner|[xnr]|))|ro)([0-9])$", item)
    if result:
        if extract:
            return (result.group(1), result.group(2), result.group(3))
        else:
            return True
    else:
        if extract:
            return ('','','')
        else:
            return False

我对def进行了一些微调,以便在调用matchPattern("boro1")时得到布尔值;如果要获取子字符串成分,则可以调用matchPattern("boro1", True),然后将得到('bo', 'ro', '1')作为结果(如果不匹配,则返回('', '', '')

关于正则表达式本身,您可以在here(regex101.com)上对其进行测试

如果要使用|正则表达式运算符,则需要使用组。在我上面使用的正则表达式中,

  • (bo|h|fr|sam|pe)表示bo,h,fr,sam或pe之一
  • ((?:cl(?:nr|eaner|[xnr]|))|ro)的意思是(?:cl(?:nr|eaner|[xnr]|))(这意味着cl后跟nr,eaner,x,n,r或什么都不是)或ro
  • ([0-9])代表一个数字(我希望此数字比\d更重要)