# PHP preg_replace_callback: Perform changes on string that is being used by the current regex in the callback

This topic is 1066 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey guys!

I'm currently doing some small kind of templating-system, and thus need to implement basic functionality such as simple loops and conditions. I'm using regular expressions since I don't really want to create a parser on my own.

My current problem is that I can't modify the string that is being used by the current regular expression action in its own callback (It's logical of course, but still).

Here is an example:

I have the string "{each42 test in tests}{hello} hello{end42}". My function is matching the first part of the loop "{each test in tests}" in a way that I know the ID of the tag (To avoid all those nested-tags problems that would require a parser), "test", and "tests".

I then extract the content of the loop "{hello} hello" by finding the end tag with the matching ID. Then I proceed to modify the extracted part, and eventually return it (Since this all happens in a preg_replace_callback callback function.). Now of course the loop-"header" is replaced by its final contents, but the original content plus the end tag still exists, and I can't delete them in the callback function itself since the regex-function just overrides them. What should I do to delete those remainders?

Thanks

Kind regards

##### Share on other sites

and I can't delete them in the callback function itself since the regex-function just overrides them

The return value of callback parameter in preg_replace_callback will replace the match:

<?php

$tbl = [ 'abc' => 'AAA', 'def' => 'BBB' ]; print preg_replace_callback('/:(.+?):/',function($m) use ($tbl){ return @$tbl[$m[1]] ?:$m[0];
},':abc: :def: :ghi:');

// displays:
// AAA BBB :ghi:


##### Share on other sites

Yeah, I know, but the problem was that it only replaces the match - And that I can't modify something that is not in the range of the match.

Solved it by changing my regex to include \g1: \{each\s(\w+)\sin\s(\w+)\s?}(.+?)\{end\g1}

##### Share on other sites

Just one more question about regexes... How do I match either "regex1" or "regex2" in the same expression? I tried doing ((regex1)|(regex2)), but it doesnt seem to work on regex101.com.

Here is the actual regex: "((\{\s?for(\w+)\s(\w+)\sin\s(\w+)\s?\}(.+?)\{end\g1\s?})|(\{\s?for(\w+)\s(\w+)\s?\=([0-9]+)\s?\;\s?(\w+)\s?(<|>|>=|<=|==|!=)\s?(\w+)\s?\;\s?(\+\+|\-\-|\|)(\w+)(\+\+|\-\-|\|)\s?\}(.+?)\{end\g1\s?}))" (Sorry for the bad formatting...)

And here are the two cases it should work with:

"{for0 index=0; i < 5; |i++}test{end0}"
"{for1 test in tests}test{end1}"

Weirdly enough, both expressions are working if they are alone. How do I make them work together?

Kind regards,
Flyverse

##### Share on other sites
See. This is how PHP got its start. And now look at the mess it's currently in. PHP7 is just barely getting a proper lexer and parser.

At this point you should stop using regular expressions and write a proper parser.
... or, you know, just use PHP:

<table>
<tr><?php
foreach ( $fields as$field ) { ?>
<th><?= $field ?></th><?php } ?> </tr> </thead> <tbody><?php foreach ($rows as $row ) { ?> <tr><?php foreach ($fields as $field ) { ?> <td><?=$row[\$field] ?></td><?php
}?>
</tr><?php
} ?>
</tbody>
</table>

Edited by fastcall22

##### Share on other sites
The problem is that I have no real clue how parsers are working. I know that I have to convert the original input into tokens and then do stuff with it, but that is as far as my knowledge goes.

1. 1
2. 2
Rutin
21
3. 3
JoeJ
18
4. 4
5. 5

• 14
• 39
• 23
• 13
• 13
• ### Forum Statistics

• Total Topics
631717
• Total Posts
3001877
×