Я в порядке с основными регулярными выражениями, но я становлюсь немного потерянным вокруг взгляда 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.
Никакого просмотра вперед / назад не требуется:
/\[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"
}
}
Я думаю, это то, к чему вы клоните:
\[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-букв, то есть.
Вам не нужно смотреть вперед / назад.
Поскольку вопрос помечен тегом 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]+)/';