Как получить все привязки матчей подгрупп с preg_match_all()?
Update/Примечание:
Я думаю, что я, вероятно, ищу, чтобы получить захваты группы в PHP.
Ссылка: Регулярные выражения PCRE с использованием подпрограмм named pattern.
(Читайте внимательно:)
У меня есть строка, содержащая переменное число сегментов (упрощенная):
$subject = 'AA BB DD '; // could be 'AA BB DD CC EE ' as well
Я хотел бы теперь совместить сегменты и возвращать их через массив совпадений:
$pattern = '/^(([a-z]+) )+$/i';
$result = preg_match_all($pattern, $subject, $matches);
Это вернет только последнее совпадение для группы захвата 2: DD
.
Есть ли способ, с помощью которого можно получить все подматричные записи (AA
, BB
, DD
) с одним выполнением регулярных выражений? Не подходит ли preg_match_all
для этого?
Этот вопрос является обобщением.
Оба $subject
и $pattern
упрощаются. Естественно, что с таким общим списком AA
, BB
,... гораздо проще извлекать другие функции (например, explode
) или с изменением $pattern
.
Но я специально спрашиваю, как вернуть все совпадения подгрупп с preg_...
-семейством функций.
Для реального жизненного случая представьте, что у вас есть несколько (вложенных) уровней варианта соответствия подшаблонов.
Пример
Это пример в псевдокоде, чтобы описать немного фона. Представьте себе следующее:
Регулярные определения токенов:
CHARS := [a-z]+
PUNCT := [.,!?]
WS := [ ]
$subject
получают на основе этих токенов. Маркировка хранится внутри массива токенов (тип, смещение,...).
Затем этот массив преобразуется в строку, содержащую один символ для токена:
CHARS -> "c"
PUNCT -> "p"
WS -> "s"
Итак, теперь можно запускать регулярные выражения на основе токенов (а не классов символов и т.д.) в индексе строки потока токенов. Например.
regex: (cs)?cp
чтобы выразить одну или несколько групп символов, за которыми следует пунктуация.
Как я теперь могу выразить самоопределяемые токены как регулярное выражение, следующим шагом было построение грамматики. Это всего лишь пример, это своего рода стиль ABNF:
words = word | (word space)+ word
word = CHARS+
space = WS
punctuation = PUNCT
Если я сейчас скомпилирую грамматику для слов в регулярное выражение (токен), я бы хотел, чтобы все подгруппы соответствовали каждому слову.
words = (CHARS+) | ( (CHARS+) WS )+ (CHARS+) # words resolved to tokens
words = (c+)|((c+)s)+c+ # words resolved to regex
Я мог бы написать код до этого момента. Затем я столкнулся с проблемой, что совпадения подгрупп содержали только их последнее совпадение.
Итак, у меня есть возможность либо самостоятельно создать автоматы для грамматики (что я хотел бы предотвратить, чтобы сохранить общие грамматические выражения), либо несколько сделать preg_match для меня каким-то образом, поэтому я могу это сэкономить.
Это в основном все. Вероятно, теперь понятно, почему я упростил вопрос.
по теме:
Ответы
Ответ 1
Попробуйте следующее:
preg_match_all("'[^ ]+'i",$text,$n);
$n[0]
будет содержать массив всех непространственных символов в тексте.
Изменить: с подгруппами:
preg_match_all("'([^ ]+)'i",$text,$n);
Теперь $n[1]
будет содержать совпадения подгрупп, которые точно совпадают с $n[0]
. Это фактически бессмысленно.
Редактировать 2: пример вложенных подгрупп:
$test = "Hello I'm Joe! Hi I'm Jane!";
preg_match_all("/(H(ello|i)) I'm (.*?)!/i",$test,$n);
И результат:
Array
(
[0] => Array
(
[0] => Hello I'm Joe!
[1] => Hi I'm Jane!
)
[1] => Array
(
[0] => Hello
[1] => Hi
)
[2] => Array
(
[0] => ello
[1] => i
)
[3] => Array
(
[0] => Joe
[1] => Jane
)
)
Ответ 2
Вы не можете извлечь подшаблоны, потому что способ, которым вы написали свое регулярное выражение, возвращает только одно совпадение (используя ^
и $
в то же время и +
в основном шаблоне).
Если вы напишете это так, вы увидите, что ваши подгруппы правильно там:
$pattern = '/(([a-z]+) )/i';
(у этого все еще есть ненужный набор круглых скобок, я просто оставил его там для иллюстрации)
Ответ 3
Есть ли способ получить все совпадения (AA, BB, DD) с одним выполнением регулярного выражения? Не подходит ли preg_match_all для этого?
Ваше текущее регулярное выражение похоже на вызов preg_match(). Вместо этого попробуйте:
$pattern = '/[a-z]+/i';
$result = preg_match_all($pattern, $subject, $matches);
В комментариях рубиново-регулярное выражение, о котором я упоминал:
sentence = %r{
(?<subject> cat | dog ){0}
(?<verb> eats | drinks ){0}
(?<object> water | bones ){0}
(?<adjective> big | smelly ){0}
(?<obj_adj> (\g<adjective>\s)? ){0}
The\s\g<obj_adj>\g<subject>\s\g<verb>\s\g<opt_adj>\g<object>
}x
md = sentence.match("The cat drinks water");
md = sentence.match("The big dog eats smelly bones");
Но я думаю, вам понадобится lexer/parser/tokenizer, чтобы делать то же самое в PHP.: - |
Ответ 4
Похожие темы: Получить повторные совпадения с preg_match_all()
Проверьте выбранный ответ плюс мой, возможно, будет полезным. Я буду дублировать его:
Из http://www.php.net/manual/en/regexp.reference.repetition.php:
Когда повторный подхват захвата повторяется, полученное значение является подстрокой, которая соответствует последней итерации.
Я лично сдаюсь и собираюсь сделать это за 2 шага.
Ответ 5
Edit
Я не понимал, о чем вы изначально просили. Вот новое решение:
$result = preg_match_all('/[a-z]+/i', $subject, $matches);
$resultArr = ($result) ? $matches[0] : array();
Ответ 6
Как насчет:
$str = 'AA BB CC';
$arr = preg_split('/\s+/', $str);
print_r($arr);
вывод:
(
[0] => AA
[1] => BB
[2] => CC
)
Ответ 7
Возможно, я неправильно понял, что вы описываете. Вы просто ищете шаблон для групп букв с пробелом между?
// any subject containing words:
$subject = 'AfdfdfdA BdfdfdB DdD';
$subject = 'AA BB CC';
$subject = 'Af df dfdA Bdf dfdB DdD';
$pattern = '/(([a-z]+)\s)+[a-z]+/i';
$result = preg_match_all($pattern, $subject, $matches);
print_r($matches);
echo "<br/>";
print_r($matches[0]); // this matches $subject
echo "<br/>".$result;
Ответ 8
Да, ваше право на решение с помощью preg_match_all
preg_match_all рекурсивно, поэтому не используйте start-with ^
и end-with $
, так что preg_match_all
помещает все найденные шаблоны в массив.
Каждая новая пара скобок добавит новые массивы, указывающие разные совпадения
используйте ?
для необязательных совпадений
Вы можете разделить разные группы шаблонов, о которых сообщалось в скобке ()
, чтобы попросить группу найти и добавить в новый массив (можно разрешить подсчет совпадений или классифицировать каждое соответствие из возвращаемого массива)
Требуется уточнение
Позвольте мне попытаться понять ваш вопрос, чтобы мой ответ соответствовал тому, что вы просите.
-
Ваш $subject
не является хорошим примером того, что вы ищете?
-
Вам нужен предварительный поиск, чтобы разделить то, что вы указали в $subject
, на 4 категории, Слова, Персонажи, Знаки препинания и . и как насчет чисел?
-
Также вы хотите, чтобы возвращаемые совпадения соответствовали смещениям совпадений?
Может ли $subject = 'aa.bb cc.dd EE FFF,GG';
лучше соответствовать реальной жизни?
Я возьму ваш основной пример в $subject
и заставлю его работать, чтобы дать вам именно то, что вы просили.
Итак, можете ли вы изменить свой $subject
, чтобы я лучше поместил все случаи, которые вы хотите сопоставить
Оригинал '/^(([a-z]+) )+$/i';
Держи меня в курсе,
вы можете проверить свои регулярные выражения здесь http://www.spaweditor.com/scripts/regex/index.php
Частичный ответ
/([a-z])([a-z]+)/i
AA BB DD CD
Array
(
[0] => Array
(
[0] => AA
[1] => BB
[2] => DD
[3] => CD
)
[1] => Array
(
[0] => A
[1] => B
[2] => D
[3] => C
)
[2] => Array
(
[0] => A
[1] => B
[2] => D
[3] => D
)
)