Как получить все привязки матчей подгрупп с preg_match_all ()?

Обновление / Примечание:

Я думаю, что я, вероятно, ищу, чтобы получить захват группы в PHP.

Ссылка: регулярные выражения PCRE с использованием подпрограмм named pattern.

(Внимательно прочитайте:)


У меня есть строка, содержащая переменное число сегментов (упрощенная):

$subject = 'AA BB DD '; // could be 'AA BB DD CC EE ' as well 

Теперь я хотел бы совместить сегменты и возвращать их через массив совпадений:

 $pattern = '/^(([az]+) )+$/i'; $result = preg_match_all($pattern, $subject, $matches); 

Это вернет только последнее совпадение для группы захвата 2: DD .

Есть ли способ, с помощью которого можно получить все подшаблоны ( AA , BB , DD ) с одним выполнением регулярных выражений? Не подходит ли preg_match_all для этого?

Этот вопрос является обобщением.

Оба параметра $subject и $pattern упрощаются. Естественно, что с таким общим списком AA , BB , .. намного легче извлекать с другими функциями (например, explode ) или с изменением $pattern .

Но я специально спрашиваю, как вернуть все подгруппы в соответствие с preg preg_... -семейством функций.

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

пример

Это пример в псевдокоде, чтобы описать немного фона. Представьте себе следующее:

Регулярные определения токенов:

  CHARS := [az]+ PUNCT := [.,!?] WS := [ ] 

$subject get tokenken на основе этих. Токенизация хранится внутри массива токенов (тип, смещение, …).

Затем этот массив преобразуется в строку, содержащую один символ для токена:

  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 для меня каким-то образом, поэтому я могу это сэкономить.

Это в основном все. Вероятно, теперь понятно, почему я упростил вопрос.


Связанный:

  • pcrepattern man page
  • Получите повторные совпадения с preg_match_all ()

Solutions Collecting From Web of "Как получить все привязки матчей подгрупп с preg_match_all ()?"

Попробуй это:

 preg_match_all("'[^ ]+'i",$text,$n); 

$n[0] будет содержать массив всех непространственных символов в тексте.

Изменить: с подгруппами:

 preg_match_all("'([^ ]+)'i",$text,$n); 

Теперь $n[1] будет содержать совпадения подгрупп, которые точно совпадают с $n[0] . На самом деле это бессмысленно.

Пример Edit2: вложенные подгруппы:

 $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 ) ) 

Вы не можете извлечь подшаблоны, потому что способ, которым вы написали свое регулярное выражение, возвращает только одно совпадение (используя одновременно ^ и $ и + на основном шаблоне).

Если вы напишете это так, вы увидите, что ваши подгруппы правильно там:

 $pattern = '/(([az]+) )/i'; 

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

Есть ли способ, чтобы я мог получить все совпадения (AA, BB, DD) с одним выполнением регулярных выражений? Не подходит ли preg_match_all для этого?

Ваше текущее регулярное выражение похоже на вызов preg_match (). Попробуйте это вместо этого:

 $pattern = '/[az]+/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. : – |

Аналогичная тема: Получите повторные совпадения с preg_match_all ()

Проверьте выбранный ответ плюс мой может быть полезным Я буду дублировать там:

С http://www.php.net/manual/en/regexp.reference.repetition.php :

Когда повторный подзапрос захвата повторяется, полученное значение представляет собой подстроку, которая соответствует последней итерации.

Я лично сдаюсь и собираюсь сделать это за 2 шага.

редактировать

Я не понимал, о чем вы изначально просили. Вот новое решение:

 $result = preg_match_all('/[az]+/i', $subject, $matches); $resultArr = ($result) ? $matches[0] : array(); 

Как насчет:

 $str = 'AA BB CC'; $arr = preg_split('/\s+/', $str); print_r($arr); 

вывод:

 ( [0] => AA [1] => BB [2] => CC ) 

Возможно, я неправильно понял, что вы описываете. Вы просто ищете шаблон для групп букв с пробелом между ними?

 // any subject containing words: $subject = 'AfdfdfdA BdfdfdB DdD'; $subject = 'AA BB CC'; $subject = 'Af df dfdA Bdf dfdB DdD'; $pattern = '/(([az]+)\s)+[az]+/i'; $result = preg_match_all($pattern, $subject, $matches); print_r($matches); echo "<br/>"; print_r($matches[0]); // this matches $subject echo "<br/>".$result; 

Да, ваше право ваше решение с помощью preg_match_all preg_match_all является рекурсивным, поэтому не используйте start-with ^ и end-with $ , так что preg_match_all помещает все найденные шаблоны в массив.

Каждая новая пара скобок добавит новые массивы, указывающие разные совпадения

использовать ? для дополнительных совпадений

Вы можете разделить разные группы шаблонов, сообщаемых с помощью скобки () чтобы попросить группу найти и добавить в новый массив (можно разрешить подсчет совпадений или классифицировать каждое соответствие из возвращаемого массива)

Требуется уточнение

Позвольте мне попытаться понять ваш вопрос, чтобы мой ответ соответствовал тому, что вы просите.

  1. Ваш $subject не является хорошим примером того, что вы ищете?

  2. Вам нужен предварительный поиск, чтобы разделить то, что вы предоставили в $subject на 4 категории , слова , символы , знаки препинания и пробелы ? и как насчет чисел ?

  3. Также вы бы хотели, чтобы возвращаемые совпадения соответствовали смещениям совпадений?

$subject = 'aa.bb cc.dd EE FFF,GG'; лучше подходит реальная жизнь?

Я возьму ваш основной пример в $subject и сделаю его работу, чтобы дать вам именно то, что вы попросили.

Так что вы можете отредактировать свой $subject чтобы я лучше поместил все случаи, которые вы хотите сопоставить

Оригинал '/^(([az]+) )+$/i';

Держите меня в курсе, вы можете проверить свои регулярные выражения здесь http://www.spaweditor.com/scripts/regex/index.php

Частичный ответ

/([az])([az]+)/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 ) )