如何在正则表达式中保留模式递归的匹配组?

问题描述 投票:0回答:1

我在尝试使用正则表达式验证输入时遇到这个问题。输入应对应于特定的类似编程的规范,该规范由函数、变量(2 种类型)和字符串组成。

这里有一些例子:

&foo
$foo(&bar)
$foo(&bar+$baz)
$foo($bar "baz" qux+$quux(&corge "grault") &garply)

现有类型:

  • $bar - 变量
  • &foo - 变量(第二种类型)
  • “baz”-字符串
  • qux - litteral 字符串
  • $quux(...) - 函数

这里的主要问题是我写了一个正则表达式,当然有回避。但是,我需要验证这样一个事实:在最终匹配本身或在其递归中,至少存在 one 第二种类型的变量 - 实际上并非如此。显然,我的正则表达式应该完全匹配输入。

这是我的正则表达式(它使用 PCRE2),后面是它的解释,以及一套供您尝试的测试:

正则表达式

(?:\$\w+(?:\((?<arg>(?R)|(?:\"[^\"]*\")|(?:[^\$\"\&\s\(\)][^\s\(\)]*))(?:(?:\+| )(?&arg))*\))?)|(?<var>\&\w+)

说明

(?:                           # function or variable and its arguments
  \$\w+                         # function or variable prefix + name (ex: $test)
  (?:                           # arguments if it's a function
    \(                            # opening parenthesis
    (?<arg>                       # first argument
      (?R)                          # function or variable
      |
      (?:\"[^\"]*\")                # string
      |
      (?:[^\$\"\&\s\(\)][^\s\(\)]*) # string literal
    )
    (?:                           # other arguments if any
      (?:\+| )                      # separator
      (?&arg)                       # argument
    )*
    \)                            # closing parenthesis
  )?
)
|
(?<var>\&\w+)                 # variable prefix + name (ex: &test)

人类可读的翻译

(                         # function or variable and its arguments
  \$\w+                     # function or variable prefix + name (ex: $test)
  MAYBE (                   # arguments if it's a function
    \(                        # opening parenthesis
    GROUP <arg> (             # first argument
      RECURSIVE                 # function or variable
      OR
      \"[^\"]*\"                # string
      OR
      [^\$\"\&\s\(\)][^\s\(\)]* # string literal
    )
    MAYBE MULTIPLE (          # other arguments if any
      \+ OR SPACE               # separator
      GROUP arg                 # argument
    )
    \)                        # closing parenthesis
  )
)
OR
GROUP <var> (\&\w+)       # variable prefix + name (ex: &test)

目标是对其进行转换,以验证组

var
在正则表达式或其递归中至少出现一次。

最好的解决方案是

(?R)
在递归中保持组匹配并将它们传递给他的父模式,我将能够检查组
var
是否与
(?(var)(*ACCEPT)|(*FAIL))
至少匹配一次。

这是我正在思考的简化版本:

(?:\w(?R)|(\d))(?(1)(*ACCEPT)|(*FAIL))
。这个正则表达式仅匹配 1 个数字,但通过“递归匹配保持”,它可以匹配任何后跟数字的字母链。

不过,似乎根本不可能。我没有找到为此的标志或令牌。

测试/示例

$test($test(test &var1 $var2) $test(jean) jean) # should full-match
$test($test(test $var1 $var2) $test(foo) bar)   # should not full-match
$test("&test")                                  # should not full-match
$test("foo&test")                               # should not full-match
$test("&test" &test)                            # should full-match
&test                                           # should full-match
$test(" &test")                                 # should not full-match
$test                                           # should not full-match
&test(foo)                                      # should not full-match
&test(&foo $bar())                              # should not full-match
$test((&test))                                  # should not full-match
$foo(bar(&baz))                                 # should not full match
$test(&test  &test)                             # should not full match
$test( &test)                                   # should not full match
$test(&test )                                   # should not full match

这是我的 regex101 测试的链接,供您尝试和测试。

regex pcre
1个回答
0
投票

因此,经过搜索,我想出了一个特定于库的解决方案。不是正则表达式,如果您遇到同样的问题,很抱歉!

为了了解更多上下文,我使用 Python 和伟大的

mrab-regex
(或简称
regex
库(而不是
re
,因为它不支持递归正则表达式等)。

并且,这个库作为一种简单的方法来获取重复组的所有成功匹配的列表,即

captures
。我只是在正则表达式匹配后立即使用它来检查正则表达式捕获组
var
是否为空:

for match in my_regex.finditer(cell):
   if not match.captures('var'):
      continue
   ...

有关

mrab-regex
及其处理重复捕获的方法的更多信息

© www.soinside.com 2019 - 2024. All rights reserved.