RegEx预测。*

时间:2013-06-18 19:35:26

标签: regex pcre

我有一个模式需要找到string1的 last 出现,除非在主题的任何地方找到string2,然后它需要第一次出现string1。为了解决这个问题,我写了这个效率低下的负面预测。

/(.(?!.*?string2))*string1/

运行需要几秒钟(在没有任何字符串出现的主题上过长时间)。有没有更有效的方法来实现这一目标?

5 个答案:

答案 0 :(得分:3)

您应该可以使用以下内容:

/string1(?!.*?string2)/

只要稍后在字符串中找不到string1,我就会匹配string2,我认为这符合您的要求。

修改:看到您的更新后,请尝试以下操作:

/.*?string1(?=.*?string2)|.*string1/

答案 1 :(得分:2)

现在好了,我已经明白了你想要什么,有点长但是优化得很快:

nutria\d.    -> string1
RABBIT       -> string2

模式(PHP中的示例)

$pattern = <<<LOD
~(?J)               # allow multiple capture groups with the same name

  ### capture the first nutria if RABBIT isn't found before ###
  ^ (?>[^Rn]++|R++(?!ABBIT)|n++(?!utria\d.))* (?<res>nutria\d.) 

  ### try to capture the last nutria without RABBIT until the end ###
  (?>
     (?>
        (?> [^Rn]++ | R++(?!ABBIT) | n++(?!utria\d.) )*
        (?<res>nutria\d.)
     )*                         # repeat as possible to catch the last nutria
     (?> [^R]++ | R++(?!ABBIT) )* $  # the end without RABBIT
  )?   # /!\important/!\  this part is optional, then only the first captured
       # nutria is in the result when RABBIT is found in this part

| # OR

  ### capture the first nutria when RABBIT is found before
  ^(?> [^n]++ | n++(?!utria\d.) )*  (?<res>nutria\d.)

~x
LOD;

$subjects = array( 'groundhog nutria1A beaver nutria1B',
                   'polecat nutria2A badger RABBIT nutria2B',
                   'weasel RABBIT nutria3A nutria3B nutria3C',
                   'vole nutria4A marten nutria4B marmot nutria4C RABBIT');

foreach($subjects as $subject) {
    if (preg_match($pattern, $subject, $match))
        echo '<br/>'.$match['res'];
}

该模式旨在尽可能快地使用原子组和具有替换的占有量词进行失败,从而避免使用最少可能的前瞻进行灾难性回溯(仅当找到nR时,它快速失败了)

答案 2 :(得分:2)

您还可以在正则表达式中执行if / else语句!

(?(?=.*string2).*(string1).*$|^.*?(string1))

<强>解释

(?                      # If
    (?=.*string2)       # Lookahead, if there is string2
    .*(string1).*$      # Then match the last string1
    |                   # Else
    ^.*?(string1)       # Match the first string1
)

如果找到string1,您将在第1组中找到它。

答案 3 :(得分:1)

试试这个正则表达式:

string1(?!.*?string1)|string1(?=.*?string2)

现场演示:http://www.rubular.com/r/uAjOqaTkYH

Regular expression image

Edit live on Debuggex

答案 4 :(得分:0)

尝试使用所有格运算符.*+,它使用更少的内存(它不存储匹配情况的整个回溯)。由于这个原因,它也可能运行得更快。