Python 正则表达式匹配一个字符串,该字符串是以分号分隔的标记序列

Python 正则表达式匹配一个字符串,该字符串是以分号分隔的标记序列,python,regex,Python,Regex,我试图生成一个Python正则表达式字符串来验证一列的值,该列是由三个字母(大写)字母数字代码列表中唯一的三个字母代码组成的逗号分隔序列,例如。该列表类似于['XA1','CZZ','BT9','WFF',…]。因此,有效列值可以是XA1,XA1;CZZ,或XA1;BT9;WFF等。一个代码不能在序列中出现多次 有效序列必须是非空的,由唯一代码组成,并且可以或不可以以终止,包括序列仅包含一个代码的情况 如果codes是代码列表,则根据该列表构造的正则表达式匹配字符串为 match_str = '

我试图生成一个Python正则表达式字符串来验证一列的值,该列是由三个字母(大写)字母数字代码列表中唯一的三个字母代码组成的逗号分隔序列,例如。该列表类似于
['XA1','CZZ','BT9','WFF',…]
。因此,有效列值可以是
XA1
XA1;CZZ,或XA1;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;')
等等


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

使用“常规”Python:

注释

  • chunks=s.strip(“;”).split(“;”)
    -删除前导/尾随
    并使用
    拆分字符串
  • if set(chunks)。issubset(code)和len(chunks)==len(set(chunks)):
    -检查我们获得的所有chunks是否都是
    code
    的子集,并确保
    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))

请参阅

这是检查字符串是否为
问题的通用非正则表达式解决方案-分离的唯一/非重复代码/令牌序列(来自固定的一组此类令牌)。字符串中的标记可以是任意顺序,但任何标记只允许出现一次,并且字符串可能以
结尾,也可能不以
结尾。字符串中的每个标记也不能被任何空格包围

示例:让令牌集成为两个字母国家代码的集合或子集,例如
{'AR','CA','GB','HK','IN','US'}
。那么,在这个问题的上下文中,“有效”字符串可以是
AR;CA
香港;美国;钙;GB
美国
香港,无效字符串可以是
AR;CA
AR;某物香港,
某物;应收账;GB;美国

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

他们应该按那个顺序来吗?尝试
match_str='^{}$'.format('?'.join(['({};){}.format(code,'?'如果code[-1]==code else'')表示代码中的代码])
No,代码也可以是任何顺序,但通常它们是一个遵循代码列表中顺序的代码序列。你明白我的意思吗?你在自相矛盾,我上面的建议行得通吗?不完全行,但几乎-所以
'XA1'
失败了,即使这应该是有效的。您的表达式似乎与尾随
的序列相匹配仅限。如果序列仅为单个代码,则可以是该值,例如
XA1
,或
CZZ
,应考虑这一点。如果序列包含多个代码,例如
CZZ;WFF
CZZ;WFF
XA1;BT9;CZZ
,则这些也应被视为有效,即使没有尾随
。好的,谢谢-这是一种更直接的解决问题的方法,但问题是关于正则表达式的。@mrs-qv7我可以创建正则表达式,但您必须保证不会使用它。我是认真的。我讨厌有害的解决方案。@mrs-qv7我添加了一个正则表达式。好的,谢谢。我不确定我是否会使用它,但我不明白为什么不应该在生产中使用regex。否则,正则表达式的意义何在?实际上,这是一种可以用简单术语描述的模式。@mrs-qv7在长的不匹配字符串上,由于回溯过多,它将冻结系统。
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))
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))
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