с помощью regex для пропускания всех символов, пока определенная последовательность букв не найдена с помощью отрицательного предвидения

Я в порядке с основными регулярными выражениями, но я становлюсь немного потерянным вокруг взгляда pos / отрицательного взгляда aheads/behinds.

Я пытаюсь вытянуть идентификатор # от этого:

[keyword stuff=otherstuff id=123 morestuff=stuff]

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

До сих пор у меня есть это:

\[keyword (?:id=([0-9]+))?[^\]]*\]

Который заботится о любых дополнительных атрибутах после идентификатора, но я не могу выяснить, как проигнорировать все между ключевым словом и идентификатором. Я знаю, что не могу пойти [^id]* Я полагаю, что должен использовать отрицательное предвидение как это (?!id)* но я предполагаю, так как это - нулевая ширина, это не продвигается оттуда. Это не работает также:

\[keyword[A-z0-9 =]*(?!id)(?:id=([0-9]+))?[^\]]*\]

Я смотрел на всем протяжении для примеров, но не нашел никого. Или возможно я имею, но они пошли до сих пор по моей голове, я даже не понял, каковы они были.

На помощь! Спасибо.

Править: Это должно соответствовать [ключевому слову stuff=otherstuff] также, где идентификатор = не существует вообще, таким образом, у меня должен быть 1 или 0 на идентификаторе # группа. Существуют также другие [otherkeywords id=32], которому я не хочу соответствовать. Документ должен соответствовать нескольким [ключевое слово id=3] всюду по документам с помощью preg_match_all.

6
задан phazei 20 July 2010 в 01:07
поделиться

3 ответа

Никакого просмотра вперед / назад не требуется:

/\[keyword(?:[^\]]*?\bid=([0-9]+))?[^\]]*?\]/

Добавлено окончание '[^]] *]' для проверки наличия реального конца тега, может быть ненужным.

Правка: добавлен \ b к id, иначе он может соответствовать [ключевое слово you-dont-want-this-guid = 123123-132123-123 id = 123]

$ php -r 'preg_match_all("/\[keyword(?:[^\]]*?\bid=([0-9]+))?[^\]]*?\]/","[keyword stuff=otherstuff morestuff=stuff]",$matches);var_dump($matches);'
array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(42) "[keyword stuff=otherstuff morestuff=stuff]"
  }
  [1]=>
  array(1) {
    [0]=>
    string(0) ""
  }
}
$ php -r 'var_dump(preg_match_all("/\[keyword(?:[^\]]*?\bid=([0-9]+))?[^\]]*?\]/","[keyword stuff=otherstuff id=123 morestuff=stuff]",$matches),$matches);'
int(1)
array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(49) "[keyword stuff=otherstuff id=123 morestuff=stuff]"
  }
  [1]=>
  array(1) {
    [0]=>
    string(3) "123"
  }
}
2
ответ дан 17 December 2019 в 06:59
поделиться

Я думаю, это то, к чему вы клоните:

\[keyword(?:\s+(?!id\b)[A-Za-z]+=[^\]\s]+)*(?:\s+id=([0-9]+))?[^\]]*\]

(Я предполагаю, что имена атрибутов могут содержать только буквы ASCII, а значения могут содержать любые символы, не являющиеся пробелами, кроме ]. )

(?:\s+(?!id\b)[A-Za-z]+=[^\]\s]+)* соответствует любому количеству пар атрибут=значение (и пробельных символов перед ними), если имя атрибута не id. \b (граница слов) ставится на случай, если имена атрибутов начинаются с id, например idiocy. На этот раз нет необходимости ставить \b перед именем атрибута, потому что вы знаете, что перед любым именем, с которым он совпадет, будет пробел. Но, как вы уже поняли, подход с опережением в данном случае излишен.

Теперь об этом:

[A-z0-9 =]

Этот A-z - либо опечатка, либо ошибка. Если вы ожидаете, что она будет соответствовать всем заглавным и строчным буквам, то так оно и есть. Но он также соответствует

'[', ']', '^', '_', '`` and '\'

... потому что их кодовые точки находятся между кодовыми точками прописных и строчных букв. ASCII-букв, то есть.

0
ответ дан 17 December 2019 в 06:59
поделиться

Вам не нужно смотреть вперед / назад.

Поскольку вопрос помечен тегом PHP, используйте preg_match_all () и сохраните совпадение в $ match.

Вот как:

<?php

  // Store the string. I single quote, in case there are backslashes I
  // didn't see.
$string = 'blah blah[keyword stuff=otherstuff id=123 morestuff=stuff]
           blah blah[otherkeyword stuff=otherstuff id=555 morestuff=stuff]
           blah blah[keyword stuff=otherstuff id=444 morestuff=stuff]';

  // The pattern is '[keyword' followed by not ']' a space and id
  // The space before id is important, so you don't catch 'guid', etc.
  // If '[keyword'  is always at the beginning of a line, you can use
  // '^\[keyword'
$pattern = '/\[keyword[^\]]* id=([0-9]+)/';

  // Find every single $pattern in $string and store it in $matches
preg_match_all($pattern, $string, $matches);

  // The only tricky part you have to know is that each entire match is stored in
  // $matches[0][x], and the part of the match in the parentheses, which is what
  // you want is stored in $matches[1][x]. The brackets are optional, since it's
  // only one line.
foreach($matches[1] as $value)
{     
    echo $value . "<br/>";
}
?>

Вывод:

123
444   

(555 пропущено, как и должно быть)

PS

Вы также можете использовать \ b вместо буквального пробела, если есть вместо этого может быть вкладка. \ b представляет границу слова ... в данном случае начало слова.

$pattern = '/\[keyword[^\]]*\bid=([0-9]+)/';
2
ответ дан 17 December 2019 в 06:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: