0

I have this code

function a($menu_item, $remove_link) {
    $pattern = 'class="(.+)"(.+)<a.+>(.+)</a>';
    if($remove_link) {
        return preg_replace($pattern, 'class="$1 selected"$2$3', $menu_item); //<- line 6
    }
    return $menu_item;
}

Which basically checks if $remove_link is true, and then removes the link and adds a class definition to $menu_item

For example, if i use

$menu_item = '<li class="menuitem first"><a href="index.php">Home</a></li>';
$menu_item = a($menu_item, true);

It should return

<li class="menuitem first selected">Home</li>;

The regex is tested and it works in Notepad++, but my function is giving this error:

Warning: preg_replace(): Delimiter must not be alphanumeric or backslash in functions.php on line 6

I saw that php patterns have to be "delimited" with slashes, so i tried to use class="/(.+)"(.+)<a.+>(.+)/</a> instead, but it gives the same error.

What am i missing? How do i use delimiters properly?

BackSlash
  • 21,927
  • 22
  • 96
  • 136

1 Answers1

1

you must put pattern delimiters at the begining and at the end of the pattern, example:

$pattern = '#class="(.+)"(.+)<a.+>(.+)</a>#';

Here # is a better choice than / because you avoid to escape all the slashes inside your pattern, but you can write:

$pattern = '/class="(.+)"(.+)<a.+>(.+)<\/a>/';

As an aside comment, your pattern will cause many backtracks:

$pattern = '~class="([^"]+)"([^>]*>)<a[^>]+>([^<]+)</a>~';

will work better.

Keep in mind that + and * are by default greedy quantifiers (i.e. they take all they can).

If I use a restricted character class instead of the dot, I can stop the greediness of the quantifiers, example

[^"]+ take all characters except ", thus it stop when a " is find.

Demo:

<?php
function a($menu_item, $remove_link) {
    //$pattern = '~class="(.+)"(.+)<a.+>(.+)</a>~';
    $pattern = '~class="([^"]+)"([^>]*>)<a[^>]+>([^<]+)<\/a>~';
    if($remove_link) {
        return preg_replace($pattern, 'class="$1 selected"$2$3', $menu_item);
    }
    return $menu_item;
}

$menu_item = '<li class="menuitem first"><a href="index.php">Home</a></li>';
echo a($menu_item, true);
Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
  • It removes the error but the text is not being replaced. Why? – BackSlash Aug 25 '13 at 16:15
  • Just checked your update, it doesn't work. What do you mean with _your pattern is false_? Do you mean it's wrong? I checked it with Notepad++ and also made a little java program that uses the same regex and it works, why doesn't it work with PHP? p.s. however, your regex doesn't work. – BackSlash Aug 25 '13 at 16:27
  • @BackSlash: after test, your pattern seems to work, but cause many backtracks (the regex engine must go forward to find the match). I have replace a `+` quantifier by a `*` in my pattern (since there is nothing between the end of the class and the `>` in the example) – Casimir et Hippolyte Aug 25 '13 at 16:40
  • I noticed your change, but it doesn't work for me. – BackSlash Aug 25 '13 at 16:42