正则表达式匹配以分号分隔的标记序列的字符串

时间:2019-06-25 12:26:11

标签: python regex

我正在尝试生成Python正则表达式字符串以验证列的值,该列是由三个字母(大写)字母数字代码(例如)组成的唯一的三个字母代码的逗号分隔序列。该列表看起来像['XA1', 'CZZ', 'BT9', 'WFF',...]。因此有效的列值可以是XA1XA1;CZZXA1;BT9;WFF;等。代码不能在序列中出现多次。

有效序列必须是非空的,由唯一的代码组成,并且可能以;结尾,也可能不以codes结尾,包括序列仅包含一个代码的情况。

如果match_str = '?'.join(['({};){}'.format(code, '?' if codes[-1] == code else '') for code in codes]) 是代码列表,则我以此为基础构造的正则表达式匹配字符串为

'(XA1;)?(CZZ;)?(BT9;)?(WFF;)?'

使用上面仅包含四个代码的示例列表,这给了我

re.match(match_str, 'XA1;')
re.match(match_str, 'XA1;WFF')
re.match(match_str, 'XA1;')

regex匹配查询的确会产生应为有效序列的非空匹配对象,例如

In [124]: re.match(match_str, 'anystring')                                                                                        
Out[124]: <_sre.SRE_Match object; span=(0, 0), match=''>

In [125]: re.match(match_str, '')                                                                                                 
Out[125]: <_sre.SRE_Match object; span=(0, 0), match=''>

In [126]: re.match(match_str, 'XA1;something')                                                                                    
Out[126]: <_sre.SRE_Match object; span=(0, 4), match='XA1;'>

if re.match(match_str, val):
     # do something
else:
     # do something else

我希望上面所有三个查询的结果都为空,因此我可以使用条件过滤掉无效值,例如

RuntimeExceptions

2 个答案:

答案 0 :(得分:1)

在您希望使具有重复块的字符串失败的情况下,应避免使用正则表达式。

使用“常规” Python:

codes = ['XA1', 'CZZ', 'BT9', 'WFF']
strs = ['XA1', 'XA1;CZZ', 'XA1;BT9;WFF;', 'XA1;XA1;', 'XA1;something']
for s in strs:
    chunks = s.strip(';').split(';')
    if set(chunks).issubset(codes) and len(chunks) == len(set(chunks)):
        print("{}: Valid!".format(s))
    else:
        print("{}: Invalid!".format(s))

请参见Python demo online

注释

  • chunks = s.strip(';').split(';')-删除前导/尾随;,并用;分割字符串
  • if set(chunks).issubset(codes) and len(chunks) == len(set(chunks)):-检查我们获得的所有块是否都是codes的子集,并确保chunks中的每个项目都是唯一的。

正则表达式解决方案-请勿在生产中使用!

import re
codes = ['XA1', 'CZZ', 'BT9', 'WFF']
block = "(?:{})".format("|".join(codes))
rex =  re.compile( r"^(?!.*\b(\w+)\b.*\b\1\b){0}(?:;{0})*;?$".format(block) )
print(rex)

strs = ['XA1', 'XA1;CZZ', 'XA1;BT9;WFF;', 'XA1;XA1;', 'XA1;something']
for s in strs:
    if rex.match(s):
        print("{}: Valid!".format(s))
    else:
        print("{}: Invalid!".format(s))

请参见Python demo

答案 1 :(得分:0)

这是一种通用的非正则表达式解决方案,用于检查字符串是否是;分隔的唯一/非重复代码/令牌序列(来自固定的此类令牌集)。字符串中的令牌可以采用任何顺序,但是任何令牌都只能出现一次,并且字符串可以以;结尾或可以不以{'AR', 'CA', 'GB', 'HK', 'IN', 'US'}结尾。字符串中的每个标记也不得包含任何空格。

示例:让令牌集为两个字母的国家代码(例如AR;CA)的集合或子集。然后,在此问题的上下文中,“有效”字符串可以是诸如HK;US;CA;GB;USHK;AR;CA之类的字符串,而无效字符串可以是诸如{{ 1}},AR;something;HK;something;AR;GB;US

def is_valid_token_sequence(s, tokens, sep=';'):
    s_tokens = [t for t in s.split(sep) if t]
    token_cntr = collections.Counter(s_tokens).values()
    return not (
        any(t not in tokens for t in s_tokens) or
        any(v > 1 for v in token_cntr)
    )

>>> is_valid_token_sequence('AR;CA', codes)                                                                                                                                                                                        
>>> True

>>> is_valid_token_sequence('HK;US;CA;GB;', codes)                                                                                                                                                                                 
>>> True

>>> is_valid_token_sequence('IN', codes)                                                                                                                                                                                           
>>> True

>>> is_valid_token_sequence('HK;', codes)                                                                                                                                                                                          
>>> True

>>> is_valid_token_sequence(' AR;CA', codes)                                                                                                                                                                                       
>>> False

>>> is_valid_token_sequence('1234;AR;X1;IN;CA', codes)                                                                                                                                                                              
>>> False

>>> is_valid_token_sequence('X1;AR;GB;US', codes)                                                                                                                                                                           
>>> False