Aid*_*len 3 python regex conditional conditional-regex
我试图用python的正则表达式库解析以下字符串:
recipe_a = 'run_list[sm_collectd::default@1.0.0]'
Run Code Online (Sandbox Code Playgroud)
使用http://pythex.org/,我正在尝试以下正则表达式:
\[(.*)::(.*)@(.*)\]
Run Code Online (Sandbox Code Playgroud)
产量:
Match 1
1. sm_collectd
2. default
3. 1.0.0
Run Code Online (Sandbox Code Playgroud)
这是问题所在:
recipe_a可以与此正则表达式进行模式匹配,但是,当字符串中不再指定@version时,它会失败.以下示例将无法匹配模式:
recipe_b = 'run_list[sm_collectd::default]'
Run Code Online (Sandbox Code Playgroud)
\\[(.\*)::(.\*)@(.\*)\\]在这种情况下失败,因为@从未匹配.有python逻辑,\\[(.\*)::(.\*)@(.\*)\\]试图并尝试后一个正则表达式\\[(.\*)::(.\*)\\].但这很愚蠢.如果我能用一个正则表达式模式完成这个,那就太好了.
我试过用条件正则表达式语句解决这个问题.我尝试过的一般语法如下:
(?(?=regex)then|else)
Run Code Online (Sandbox Code Playgroud)
首先 ?是先行断言:没有消费的匹配.所以我们可以对@符号进行条件匹配.
如果@匹配则执行\\[(.\*)::(.\*)@(.\*)\\],否则执行\\[(.\*)::(.\*)\\].
程序化解决方案
kitchen_recipe = 'recipe[my_cookbook::default@0.1.0]'
recipe = kitchen_recipe.strip('recipe[').strip(']')
if '@' in recipe:
cookbook, recipe, cookbook_version = tuple(re.split('::|@', recipe))
else:
cookbook, recipe = tuple(re.split('::', recipe))
cookbook_version = None # no version specified
Run Code Online (Sandbox Code Playgroud)
REGEX解决方案
kitchen_recipe = 'recipe[my_cookbook::default@0.1.0]'
run_list_pattern = '\[(.*)::([^@]*)@?([0-9.]*)\]'
cookbook, recipe, cookbook_version = re.search(test_list_pattern,
kitchen_recipe).groups()
Run Code Online (Sandbox Code Playgroud)
一些小的改动应该适合您的目的; 尝试\[(.*)::([^@]*)(?:@(.*))?\]
run_list[sm_collectd::default] 产量
sm_collectddefaultrun_list[sm_collectd::default@1.0.0] 产量
sm_collectddefault1.0.0我把决赛@(.*)改成了(?:@(.*))?.附加(?:)是一个非捕获基团,下面?的意思是"匹配0或1倍".
我也改变了第一个(.*)进入([^@]*),这意味着匹配任何东西,但一个@多次越好,这样它不会把所有default@1.0.0的厨师配方名.
编辑:正如@gregory指出的那样,你可以避免非捕获组.你可以用\[(.*)::([^@]*)@?(.*)\].
如果您想将版本号限制为仅数字和.s : \[(.*)::([^@]*)@?([0-9.]*)\].