首页 > 解决方案 > 正则表达式匹配一个以分号分隔的标记序列的字符串

问题描述

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

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

如果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;')

等等

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

标签: pythonregex

解决方案


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

使用“常规”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 演示

注意事项

  • 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 演示


推荐阅读