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!

Mark
  • 3,653
  • 10
  • 30
  • 62

2 Answers2

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);
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • How could you get the `$in` populated with subject ? – The Alpha Jun 24 '12 at 03:55
  • @SheikhHeera That should already be there. I usually use `$in` and `$out` to show where the data goes in and comes out. – Niet the Dark Absol Jun 24 '12 at 03:55
  • 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. http://ideone.com/K71TV – Mark Jun 24 '12 at 03:57
  • That's because you're using an old version of PHP. I'll edit with a backward-compatible version. – Niet the Dark Absol Jun 24 '12 at 03:57
  • @Kolink Amazing! Works perfectly. Thanks so much, will accept once the system timer lets me – Mark Jun 24 '12 at 04:00
  • @Kolink : why have you used the word " is " in the 2nd line of your code . I'am a newbie , please help with that . – Neetz Jun 14 '13 at 06:11
  • `i` is a flag to make it case-insensitive. `s` allows `.` to match newlines. – Niet the Dark Absol Jun 14 '13 at 14:36
  • Please, not another needless create_function()! 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._ [Doc](http://php.net/manual/en/function.create-function.php) – Michael Probst May 21 '15 at 15:29
  • 2
    @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 ;) – Niet the Dark Absol May 21 '15 at 17:43
  • @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. – Michael Probst May 27 '15 at 19:35
  • 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! – Filip OvertoneSinger Rydlo May 30 '16 at 12:50
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.

Community
  • 1
  • 1
Amal Murali
  • 75,622
  • 18
  • 128
  • 150
  • 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://stackoverflow.com/a/14383726/957246 – trapper_hag Jun 02 '20 at 11:11