Подтвердить что ты не робот

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

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


по теме:

4b9b3361

Ответ 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
        )

)