Search code examples
phpregexpreg-replace-callback

Preg_replace and Preg_replace_callback


I'm updating my coding and moving away from preg_replace towards the function preg_replace_callback. On the first I used two arrays, which replaced all the matches in a piece of text.

I have setup the following new piece of code, but I am running into some issues:

<?php
$inhoud = " dit is een test versie, waarin [alum] staat [alum] & [fotoalbums] om [intern=test]te[/intern] vervangen<p>";

function parse_callback($match) {
        $hit = $match[0];
        switch ($hit){
                case '[alum]': 
                        return "<a href=\"/linktype1/\">link1</a>";
                        break;
                case '[fotoalbums]':
                        return "<a href=\"/linktype2/\">link2</a>";
                        break;
                case '[intern]':
                        return "<a href=\"". $match[1] ."\">$match[2]</a>";
                        break;
                default:
                        //return "UNKNOWN:$match";
                        return var_dump($match);
        }
}

$Patroon = "'\[intern=(.*?)\](.*?)\\[\/intern\]'";
$Patroon = "'\[fotoalbums\]'";
$Patroon = "'\[alum\]'";

$inhoud = preg_replace_callback($Patroon, parse_callback, $inhoud);
?>

The later two in the $Patroon are no issue, these will be updated, but I'm unable to update the first, as the match being found will be the complete string. The $match will also contain the pieces of text from $inhoud on which is has matched (.*?), but I'm unable to process these in the switch.

Any suggestions on how to resolve this issue or a better approach to the coding. The above example is just a few options which will be matched, the actual list is much larger.


Solution

  • First of all, you should pass the function name as a string: "parse_callback".

    As you've noticed, match[0] will return the whole matched text ("[intern=test]te[/intern]"). You could capture the tag name in a group:

    $Patroon = "'\[(intern)=(.*?)\](.*?)\[/intern\]'";
    
    • Notice the parentheses in (intern)

    This way, the tag name will be returned by $match[1].

    And using this approach to all patterns:

    $Patroon = array(
        "'\[(intern)=(.*?)\](.*?)\[/intern\]'",
        "'\[(fotoalbums|alum)\]'"
    );
    

    Code

    <?php
    $inhoud = " dit is een test versie, waarin [alum] staat [alum] & [fotoalbums] om [intern=test]te[/intern] vervangen<p>";
    
    function parse_callback($match) {
            //check the value of the first capture
            $hit = $match[1];
            switch ($hit){
                    case 'alum': 
                            return "<a href=\"/linktype1/\">link1</a>";
                            break;
                    case 'fotoalbums':
                            return "<a href=\"/linktype2/\">link2</a>";
                            break;
                    case 'intern':
                            return "<a href=\"$match[2]\">$match[3]</a>";
                            break;
                    default:
                            //return "UNKNOWN:$match";
                            return var_dump($match);
            }
    }
    
    $Patroon = array(
        "'\[(intern)=(.*?)\](.*?)\[/intern\]'",
        "'\[(fotoalbums|alum)\]'"
    );
    
    $inhoud = preg_replace_callback($Patroon, "parse_callback", $inhoud);
    
    echo $inhoud;
    ?>
    

    Output

     dit is een test versie, waarin <a href="/linktype1/">link1</a> staat <a href="/linktype1/">link1</a> & <a href="/linktype2/">link2</a> om <a href="test">te</a> vervangen<p>
    

    ideone demo