preg_replace using the matched keywords

I am attempting to use preg_match to find and replace based on some parts that are found in the string, I am able to do this by sepparating the script into different patterns but I wonder if this can be done with ony one pattern.

For instance I strings like this

{container id=1 class=basic}
{container class=advanced id=5}

and I should be translating that into
<div class=“basic”><a href=“/index.php?id=1”></a></div>
<div class=“advanced”><a href=“/index.php?id=5”></a></div>

At the moment I am able to do them but they always have to respect the order of
{container class=someclassname id=someid}

if by any chance the user enters
{container id=someid class=someclassname}

Then the script does not work

I found that enclosing the pattern in parenthesis then I can do something like
$replcement=‘<div class=“${1}”><a href=“/index.php?id=${2}”></a></div>’;

but if my pattern looks something like this
({test) (id=\d*|class=\w*) (id=\d*|class=\w*)(})

How could I know if they first entered the id or the class name

Just to qualify, are those target strings actually part of longer strings?


$target = “Start of the string {container id=1 class=basic} and then there is this case
{container class=advanced id=5} there may be other cases besides”;

I would assume this is a method of templating, so would assume that the replace is to be done over a considerable block of string.

Me too, but I thought I would ask.

Yres they are definitely part of longer strings

Is ID always numeric and class always a string?

Will that always be the case, or may you in the future decide to permit another attribute?

Thinks: hang on, isn’t id=5 illegal in terms of the dom? hmmmm… changed between html 4.01 and html 5 , now I did not know that.

yes, yes it is invalid to have id=1 I just typed it like that to make things a little bit easier to understand but in fact I have something like this {container 1 basic} where the integer is always a 1-3 digit number and the other part is always a word with characters from a-z

OK, now I am confused, is the target {container 1 basic} or is it {container id=1 class=basic} ?

It is {container 1 basic}

I think one solution is to use a callback function to sort out which is an integer and which is a string.


// set up some test strings

$strings[] = "The string is {container 1 basic} but could also contain {container advanced 99} for example";
$strings[] = "This should fail {container 1111 basic}"; // > 999
$strings[] = "This should fail {11 basic}"; // no container word
$strings[] = "This should fail {container 11 basic ";  // missing end bracket
$strings[] = "This should fail { container 11 basic} "; // space prior to first bracket
$strings[] = "This should fail container 11 basic}"; // missing first bracket
$strings[] = "Should THIS fail {container 11 22}, or what should it do then?"; // a quandry?
$strings[] = "Should THIS fail {container silly basic}"; // ditto

// create the callback function
function make_divs($matches)
if( (int)$matches[1] > 0 ){
  $id = $matches[1];
  $class = $matches[2];
  $id = $matches[2];
  $class = $matches[1];

return "<div class=$class><a href=index.php?id=$id></a></div>";

// loop through the test cases, view page source to see the results properly

foreach( $strings as $string){

      echo  preg_replace_callback(
            "#{container (\\d{1,3}|[a-z]*) ([a-z]*|\\d{1,3})}#", 
            $string) , PHP_EOL;


At its simplest that should work, but you will notice that the LAST TWO example strings possibly should fail, but do not – as things stand, in order to keep the solution simple to follow.

The more varied and real worldly your test strings are the more complex the solution will probably end up becoming.

I leave it there because it is now up to you to post the test cases showing where you expect to pass and where you expect to fail.


thank you for all your help, the setting will be controlled so there is only one person entering this strings and he seems to be doing it fine so far.

Also a slight note there; make sure your person doing the entering doesnt try to enter an ID of 0 :wink: