Reputation: 4272
I want to match 2 results in a single string, both need to exist for something to be returned but the order in which they are in the string is not important.
$row = '[one]This[/one][two]That[/two]';
preg_match_all('#(\[one\](.*?)\[/one\])(\[two\](.*?)\[/two\])#', $row, $result_match);
If $row was instead. $row = '[two]That[/two][one]This[/one]';
is it possible for the preg_match_all to find the results anyway.
I need to capture THAT and THIS and know if it is inside one or two. Capture either both one and two or only capturing a single of the one or two would tell me which one the text was inside.
Update:
The final result I settled on is:
#[(?!\1)((?:one|two))](.*?)[\/\1]#
Users after this new feature released now want to be able to nest the commands. I have tried changing ?:one|two to ?!.one|two to use negative look forward to match the final result in the string.
They want to be able to do this:
[one]This[one]This Again[/one][two]That Again[/two][/one][two]That[/two]
The desired capture would be
This[one]This Again[/one][two]That Again[/two]
And
[two]That[/two]
Update 2:
This is the full scope of what I am trying to do.
[run][one]This[/one][two]That[/two][/run]
[run][one]This 2[/one][two]That 2[/two][/run]
[run][one]IF THIS RESULT DO THIS [run][one]This[/one][two]That[/two][/run][/one][two]IF THIS RESULT DO THAT [run][one]This[/one][two]That[/two][/run][/two][/run]
The users do this all in one post and they want to be able to do nested runs. The desired results would be..
[one]This[/one][two]That[/two]
[one]This 2[/one][two]That 2[/two]
[one]IF THIS RESULT DO THIS [run][one]This[/one][two]That[/two][/run][/one][two]IF THIS RESULT DO THAT [run][one]This[/one][two]That[/two][/run][/two]
I can foreach the results to handle nested runs. Is this even possible?
Upvotes: 2
Views: 129
Reputation: 785611
You may use this regex with a negative lookahead, capture group and back-reference:
~(?:.*?\[(?!\1)([12])\].*?\[/\1\]){2}~
Regex Description:
(?:
: Start a non-capture group
.*?
: Match 0 or more characters (non-greedy)\[
: Match [
(?!\1)
: Assert that we don't have text same as back-reference \1
ahead([12])
: Match 1
or 2
and capture in group #1\]
: Match ]
.*?
: Match 0 or more characters (non-greedy)\[
: Match [
/\1
: Using back-reference, match same text as what we have in capture group #1\]
: Match ]
)
: End non-capture group{2}
: Match 2 instances of above non-capture groupUpdate 2:
After your update above regex won't work anymore as you want to capture text between the tags. You may use: this regex:
~(?|\[one\](.*?)\[/one\].*?\[two\](.*?)\[/two\]|\[two\](.*?)\[/two\].*?\[one\](.*?)\[/one\])~
Your captured groups are available in #1 and #2.
Update 3:
Based on recent conversation you may use this recursive regex to match bbcode data between outermost [run]
and [/run]
tags:
$re = '~\[(run)] ( (?: (?: (?! \[/?\1] ) . )* | (?R) )* ) \[/\1]~sx';
Read more about recursive patterns
Upvotes: 1