Регулярное выражение PHP - повторяющееся совпадение группы - PullRequest
10 голосов
/ 05 февраля 2010

У меня есть строка, которая может выглядеть примерно так:

$r = 'Filed under: <a>Group1</a>, <a>Group2</a>';

Вот регулярное выражение, которое я использую до сих пор:

preg_match_all("/Filed under: (?:<a.*?>([\w|\d|\s]+?)<\/a>)+?/", $r, $matches);

Я хочу, чтобы регулярное выражение внутри () продолжало делать совпадения, обозначенные +? в конце. Но это просто не поможет. :: вздыхать ::

Любые идеи. Я знаю, что должен быть способ сделать это в одном регулярном выражении вместо того, чтобы разбивать его.

Ответы [ 4 ]

9 голосов
/ 05 февраля 2010

Просто для удовольствия, вот регулярное выражение, которое будет работать с одним preg_match_all:

'%(?:Filed under:\s*+|\G</a>)[^<>]*+<a[^<>]*+>\K[^<>]*%`

Или в более читаемом формате:

'%(?:
      Filed under:   # your sentinel string
    |                
      \G             # NEXT MATCH POSITION
      </a>           # an end tag
  )
  [^<>]*+          # some non-tag stuff     
  <a[^<>]*+>       # an opening tag
  \K               # RESET MATCH START
  [^<>]+           # the tag's contents
%x'

\G соответствует положению, с которого должна начинаться следующая попытка матча, обычно это точка, где закончился предыдущий успешный матч (но если предыдущий матч был нулевой длины, он поднимается вперед еще на одну). Это означает, что регулярное выражение не будет совпадать с подстрокой, начинающейся с </a> до после , и совпадает с подстрокой, начинающейся с Filed under: хотя бы один раз.

После того, как сторожевая строка или конечный тег были сопоставлены, [^<>]*+<a[^<>]*+> потребляет все, вплоть до следующего начального тега. Затем \K подменяет начальную позицию, так что совпадение (если оно есть) начинается после тега <a> (это похоже на позитивный взгляд сзади, но более гибкий). Наконец, [^<>]+ соответствует содержимому тега и переносит позицию соответствия до конечного тега, так что \G может соответствовать.

Но, как я уже сказал, это просто для развлечения. Если у вас нет для выполнения работы в одном регулярном выражении, вам лучше использовать многоэтапный подход, такой как используемый @codaddict; он более читабелен, более гибок и удобен в обслуживании.

\K ссылка
\G ссылка

РЕДАКТИРОВАТЬ: Хотя ссылки, которые я дал, относятся к документации по Perl, эти функции также поддерживаются PHP - или, точнее, библиотекой PCRE. Я думаю, что документы на Perl немного лучше, но вы также можете прочитать об этом в руководстве PCRE .

7 голосов
/ 05 февраля 2010

Попробуйте:

<?php

$r = 'Filed under: <a>Group1</a>, <a>Group2</a>, <a>Group3</a>, <a>Group4</a>';

if(preg_match_all("/<a.*?>([^<]*?)<\/a>/", $r, $matches)) {
    var_dump($matches[1]); 
}

?>

выход:

array(4) {
  [0]=>
  string(6) "Group1"
  [1]=>
  string(6) "Group2"
  [2]=>
  string(6) "Group3"
  [3]=>
  string(6) "Group4"
}

EDIT:

Поскольку вы хотите включить в поиск строку 'Filed under', чтобы однозначно идентифицировать совпадение, вы можете попробовать это, я не уверен, что это можно сделать с помощью одного вызова preg_match

// Since you want to match everything after 'Filed under'
if(preg_match("/Filed under:(.*)$/", $r, $matches)) {
    if(preg_match_all("/<a.*?>([^<]*?)<\/a>/", $matches[1], $matches)) {
        var_dump($matches[1]); 
    }
}
2 голосов
/ 05 февраля 2010
$r = 'Filed under: <a>Group1</a>, <a>Group2</a>'
$s = explode("</a>",$r);
foreach ($s as $k){
    if ($k){
        $k=explode("<a>",$k);
        print "$k[1]\n";
    }
}

выход

$ php test.php
Group1
Group2
1 голос
/ 05 февраля 2010

Я хочу, чтобы регулярное выражение внутри () продолжало делать совпадения, обозначенные знаком +? в конце.

+? - это ленивый квантификатор - он будет соответствовать как можно меньше раз. Другими словами, только один раз.

Если вы хотите сопоставить несколько раз, вам нужен жадный квантификатор - +.

Также обратите внимание, что ваше регулярное выражение не совсем работает - совпадение завершается неудачно, как только встречается запятая между тегами, потому что вы не учли это. Это, вероятно, нуждается в исправлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...