标签: conditional-regex

是否可以删除已经匹配的捕获组,使其不参与?

在PCRE2或支持前向反向引用的任何其他正则表达式引擎中,是否可以将在先前循环迭代中匹配的捕获组更改为非参与捕获组(也称为未设置捕获组或未捕获组),导致测试该组的条件与其"假"条款相匹配而不是它们的"真实"条款?

例如,采用以下PCRE正则表达式:

^(?:(z)?(?(1)aa|a)){2}
Run Code Online (Sandbox Code Playgroud)

当输入字符串时zaazaa,它根据需要匹配整个字符串.但是当zaaaa我吃饱时,我希望它能够匹配zaaa; 相反,它匹配zaaaa整个字符串.(这只是为了举例说明.当然这个例子可以处理,^(?:zaa|a){2}但不是重点.捕获组擦除的实际用法往往是循环,最常做的远远超过2次迭代.)

这样做的另一种方法,也不能按预期工作:

^(?:(?:z()|())(?:\1aa|\2a)){2}
Run Code Online (Sandbox Code Playgroud)

请注意,当循环"展开"时,这两个都可以正常工作,因为它们不再需要擦除已经进行的捕获:

^(?:(z)?(?(1)aa|a))(?:(z)?(?(2)aa|a))
^(?:(?:z()|())(?:\1aa|\2a))(?:(?:z()|())(?:\3aa|\4a))
Run Code Online (Sandbox Code Playgroud)

因此,不是能够使用最简单的条件形式,而是必须使用更复杂的条件,这只适用于此示例,因为"true"匹配z是非空的:

^(?:(z?)(?(?!.*$\1)aa|a)){2}
Run Code Online (Sandbox Code Playgroud)

或者只使用模拟条件:

^(?:(z?)(?:(?!.*$\1)aa|(?=.*$\1)a)){2}
Run Code Online (Sandbox Code Playgroud)

我已经走遍所有的文件我能找到,而且似乎没有甚至没有提及或这种行为明确描述(即捕获环路内进行通过循环迭代坚持,即使他们失败时,重新拍摄).

它与我的直觉预期不同.我会实现它的方法是,评估捕获组与0次重复将擦除/复位它(这样这可能发生在任何捕获基团与*,?{0,N}量词),但是跳过它由于内的相同的并行其它替换在上一次迭代中获得捕获的组不会擦除它.因此,如果它们包含至少一个元音,那么这个正则表达式仍将匹配单词:

\b(?:a()|e()|i()|o()|u()|\w)++\1\2\3\4\5\b
Run Code Online (Sandbox Code Playgroud)

但是跳过一个捕获组,因为它位于一个未评估的替代组中,该组使用非零重复进行评估,嵌套在上一次迭代期间捕获组占用一个值的组中,删除/取消设置它,所以这个正则表达式能够\1在循环的每次迭代中捕获或擦除组:

^(?:(?=a|(b)).(?(1)_))*$
Run Code Online (Sandbox Code Playgroud)

并匹配字符串,如aaab_ab_b_aaaab_ab_aab_b_b_aaa.但是,前向引用的方式实际上是在现有引擎中实现的,它匹配aaaaab_a_b_a_a_b_b_a_b_b_b_.

我想知道这个问题的答案,不仅因为它对构建正则表达式很有用,而且因为我编写了自己的正则表达式引擎,目前ECMAScript兼容一些可选的扩展(包括分子前瞻(?*),即非原子前瞻,据我所知,没有其他引擎有),我想继续添加其他引擎的功能,包括前向/嵌套后向引用.我不仅希望我的前向反向引用的实现与现有实现兼容,而且如果没有一种方法可以在其他引擎中擦除捕获组,我可能会在我的引擎中创建一种不冲突的方法与其他现有的正则表达式功能.

需要明确的是:只要有足够的研究和/或引用资料来支持,任何主流引擎都无法做到这一点的答案是可以接受的.的回答说,它可能的将是国家要容易得多,因为它需要一个例子.

关于非参与捕获组是什么的一些信息:
http://blog.stevenlevithan.com/archives/npcg-javascript-这篇文章最初向我介绍了这个想法.
https://www.regular-expressions.info/backref2.html - 本页的第一部分给出了简要说明.
在ECMAScript/Javascript正则表达式中,对NPCG的反向引用始终匹配(进行零长度匹配).在几乎所有其他正则表达式的味道,他们无法匹配任何东西.

regex pcre regex-group conditional-regex

9
推荐指数
3
解决办法
320
查看次数

在python中,如何使用正则表达式有条件地模式匹配

我试图用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.]*)\]' …
Run Code Online (Sandbox Code Playgroud)

python regex conditional conditional-regex

3
推荐指数
1
解决办法
1239
查看次数