Change the patter to be non-greedy with .? and also switch from preg_match to preg_match_all
$str = 'abc 123 &*First part*& abc 123 &*Second part*& 123 abc';
$p = '#(?<=&\*).*?(?=\*&)#';
if (preg_match_all($p, $str, $m))
{
echo '<pre>' . print_r($m, 1) . '</pre>';
}
This will get all texts between & and &, assuming there are no nested occurences, like
$str = 'One &*First half &*Nested part*& Second half*&';
since that would match against
First half &*Nested part
To avoid that, you'd need to do something like this instead
function get_nested_between($s, $stoken, $etoken)
{
# Finding index of '&*' in '01 &*56' gives 3, but we want to cut from 5
$slen = strlen($stoken);
# escape the delimiters so that they are safe for use with preg
$stoken = preg_quote($stoken, '#');
$etoken = preg_quote($etoken, '#');
$sp = "#$stoken#";
$ep = "#$etoken#";
$start = array();
$end = array();
# if no starting delimiter is found, we are done
if (!preg_match_all($sp, $s, $start_match, PREG_OFFSET_CAPTURE))
{
return false;
}
# if no ending delimiter is found, we are done
if (!preg_match_all($ep, $s, $end_match, PREG_OFFSET_CAPTURE))
{
return false;
}
# put starting indices in array $start
foreach ($start_match[0] as $i)
{
$start[] = $i[1];
}
# put ending indices in array $start
foreach ($end_match[0] as $i)
{
$end[] = $i[1];
}
$index = array();
while(($len = count($start)))
{
$nested_temp = array();
for ($i = 0; $i < $len; ++$i)
{
$nested = $i;
# if the next starting delimiter index is lower than the current ending delimiter index
# there is an occurence of a nested string
while (($nested + 1) < $len && $start[$nested + 1] < $end[$i])
{
++$nested;
}
# This will insert nested parts before the surrounding part, which means
# the start index will be higher for nested strings than for the containing
# string. Could be solved here if you wish, but I went with the lazy
# solution of reordering the array later on.
$start_index[] = $start[$nested] + $slen;
$end_index[] = $end[$i];
$last_pos = count($start_index) - 1;
$index[] = array($start_index[$last_pos], $end_index[$last_pos]);
array_splice($start, $nested, 1);
array_splice($end, $i, 1);
--$len;
}
}
# Deal with indices being out of order for nested parts.
array_multisort($start_index, SORT_ASC, SORT_NUMERIC, $end_index, SORT_ASC, SORT_NUMERIC, $index);
$out = array();
foreach ($index as $i)
{
$out[] = substr($s, $i[0], $i[1] - $i[0]);
}
return $out;
}
$str = 'abc 123 &*First part*& abc 123 &*Second part*& 123 abc&*Nested first half &*Nested inner*&Nested second half*& qwerty';
echo $str . '<br/><br/>';
$parts = get_nested_between($str, '&*', '*&');
echo '<pre>'.print_r($parts,1).'</pre>';