How to use preg_replace_callback?
Asked Answered
C

2

42

I have the following HTML statement

[otsection]Wallpapers[/otsection]
WALLPAPERS GO HERE

[otsection]Videos[/otsection]
VIDEOS GO HERE

What I am trying to do is replace the [otsection] tags with an html div. The catch is I want to increment the id of the div from 1->2->3, etc..

So for example, the above statement should be translated to

<div class="otsection" id="1">Wallpapers</div>
WALLPAPERS GO HERE

<div class="otsection" id="2">Videos</div>
VIDEOS GO HERE

As far as I can research, the best way to do this is via a preg_replace_callback to increment the id variable between each replacement. But after 1 hour of working on this, I just cant get it working.

Any assistance with this would be much appreciated!

Celka answered 24/6, 2012 at 3:46 Comment(0)
R
55

Use the following:

$out = preg_replace_callback(
    "(\[otsection\](.*?)\[/otsection\])is",
    function($m) {
        static $id = 0;
        $id++;
        return "<div class=\"otsection\" id=\"ots".$id."\">".$m[1]."</div>";
    },
    $in);

In particular, note that I used a static variable. This variable persists across calls to the function, meaning that it will be incremented every time the function is called, which happens for each match.

Also, note that I prepended ots to the ID. Element IDs should not start with numbers.


For PHP before 5.3:

$out = preg_replace_callback(
    "(\[otsection\](.*?)\[/otsection\])is",
    create_function('$m','
        static $id = 0;
        $id++;
        return "<div class=\"otsection\" id=\"ots".$id."\">".$m[1]."</div>";
    '),
    $in);
Rolfe answered 24/6, 2012 at 3:49 Comment(11)
How could you get the $in populated with subject ?Cao
@SheikhHeera That should already be there. I usually use $in and $out to show where the data goes in and comes out.Rolfe
Thanks it looks great and should work, but I keep getting an unexpected T_FUNCTION error, but the quotes and escaped quotes all look good. ideone.com/K71TVCelka
That's because you're using an old version of PHP. I'll edit with a backward-compatible version.Rolfe
@Kolink Amazing! Works perfectly. Thanks so much, will accept once the system timer lets meCelka
@Kolink : why have you used the word " is " in the 2nd line of your code . I'am a newbie , please help with that .Sup
i is a flag to make it case-insensitive. s allows . to match newlines.Rolfe
Please, not another needless <code>create_function()</code>! Please note: Caution This function internally performs an eval() and as such has the same security issues as eval(). Additionally it has bad performance and memory usage characteristics. DocSmirk
@MichaelProbst That's why you should upgrade to a version of PHP that has anonymous function support (5.3 or newer). If you're still using 5.2, you have bigger problems than an errant eval in disguise ;)Rolfe
@NiettheDarkAbsol : I agree you should be using PHP 5.3+ for security reasons, but even with 5.3+ you still have an eval()-Problem if you use function_create() instead of an anonymous function. And the example above shows function_create(), that's why I warn.Smirk
Thanx for the part "For PHP before 5.3:" ! ... I have v.5.2.6 ... so I have slightly modified the code like this - and it works!Riane
P
37

Note: The following is intended to be a general answer and does not attempt to solve the OP's specific problem as it has already been addressed before.

What is preg_replace_callback()?

This function is used to perform a regular expression search-and-replace. It is similar to str_replace(), but instead of plain strings, it searches for a user-defined regex pattern, and then applies the callback function on the matched items. The function returns the modified string if matches are found, unmodified string otherwise.

When should I use it?

preg_replace_callback() is very similar to preg_replace() - the only difference is that instead of specifying a replacement string for the second parameter, you specify a callback function.

Use preg_replace() when you want to do a simple regex search and replace. Use preg_replace_callback() when you want to do more than just replace. See the example below for understanding how it works.

How to use it?

Here's an example to illustrate the usage of the function. Here, we are trying to convert a date string from YYYY-MM-DD format to DD-MM-YYYY.

// our date string
$string  = '2014-02-22';

// search pattern
$pattern = '~(\d{4})-(\d{2})-(\d{2})~';

// the function call
$result = preg_replace_callback($pattern, 'callback', $string);

// the callback function
function callback ($matches) {
    print_r($matches);
    return $matches[3].'-'.$matches[2].'-'.$matches[1];
}

echo $result;

Here, our regular expression pattern searches for a date string of the format NNNN-NN-NN where N could be a digit ranging from 0 - 9 (\d is a shorthand representation for the character class [0-9]). The callback function will be called and passed an array of matched elements in the given string.

The final result will be:

22-02-2014

Note: The above example is for illustration purposes only. You should not use to parse dates. Use DateTime::createFromFormat() and DateTime::format() instead. This question has more details.

Perlman answered 7/2, 2014 at 15:2 Comment(1)
One thing that seems obvious once you know it, but might be worth noting if you're just starting with preg_ functions, is that in the example $matches starts at 1 rather than 0 because 0 contains the entire string that was matched. See https://mcmap.net/q/391537/-why-preg_match-returns-first-match-at-index-1-not-0-of-returned-arrayEnzyme

© 2022 - 2024 — McMap. All rights reserved.