How to get all captures of subgroup matches with preg_match_all()? [duplicate]

空扰寡人 提交于 2019-11-27 01:49:50

Try this:

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

$n[0] will contain an array of all non-space character groups in the text.

Edit: with subgroups:

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

Now $n[1] will contain the subgroup matches, that are exactly the same as $n[0]. This is pointless actually.

Edit2: nested subgroups example:

$test = "Hello I'm Joe! Hi I'm Jane!";
preg_match_all("/(H(ello|i)) I'm (.*?)!/i",$test,$n);

And the result:

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
        )

)

Similar thread: Get repeated matches with preg_match_all()

Check the chosen answer plus mine might be useful I will duplicate there:

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

When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration.

I personally give up and going to do this in 2 steps.

EDIT:

I see in that other thread someone claimed that lookbehind method is able doing it.

Is there a way that I can retrieve all matches (AA, BB, DD) with one regex execution? Isn't preg_match_all not suitable for this?

Your current regex seems to be for a preg_match() call. Try this instead:

$pattern = '/[a-z]+/i';
$result = preg_match_all($pattern, $subject, $matches);

Per comments, the ruby regex I mentioned:

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");

But I think you'll need a lexer/parser/tokenizer to do the same kind of thing in PHP. :-|

You can't extract the subpatterns because the way you wrote your regex returns only one match (using ^ and $ at the same time, and + on the main pattern).

If you write it this way, you'll see that your subgroups are correctly there:

$pattern = '/(([a-z]+) )/i';

(this still has an unnecessary set of parentheses, I just left it there for illustration)

Edit

I didn't realize what you had originally asked for. Here is the new solution:

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

How about:

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

output:

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

I may have misunderstood what you're describing. Are you just looking for a pattern for groups of letters with whitespace between?

// 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;

Yes your right your solution is by using preg_match_all preg_match_all is recursive, so dont use start-with^ and end-with$, so that preg_match_all put all found patterns in an array.

Each new pair of parenthesis will add a New arrays indicating the different matches

use ? for optional matches

You can Separate different groups of patterns reported with the parenthesis () to ask for a group to be found and added in a new array (can allow you to count matches, or to categorize each matches from the returned array )

Clarification required

Let me try to understand you question, so that my answer match what you ask.

  1. Your $subject is not a good exemple of what your looking for?

  2. You would like the pregmatch search, to split what you provided in $subject in to 4 categories , Words, Characters, Punctuation and white spaces ? and what about numbers?

  3. As well you would like The returned matches, to have the offsets of the matches specified ?

Does $subject = 'aa.bb cc.dd EE FFF,GG'; better fit a real life exemple?

I will take your basic exemple in $subject and make it work to give your exactly what your asked.

So can you edit your $subject so that i better fit all the cases that you want to match

Original '/^(([a-z]+) )+$/i';

Keep me posted, you can test your regexes here http://www.spaweditor.com/scripts/regex/index.php

Partial answer

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

)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!