skip to Main Content

Hey guys I would like your help with with preg_match and replace function I have this:

$replacement="NEW TEXT";
<p data-edit="1">TEXT A</p>
<div data-edit="2">TEXT B</div>

And I need to find div or p or anything with data-edit attribute that equals to some number, in this case for example 1 and replace the text inside for $replacement.

2

Answers


  1. Initiate by setting the HTML content and the text intended for replacement, identify the specific number within the ‘data-edit‘ attribute targeting, and employ a regular expression to isolate the complete HTML element. This process involves capturing both the opening and closing tags, particularly pinpointing elements with a ‘data-edit‘ attribute corresponding to the target number. Then utilize ‘preg_replace_callback‘ to invoke a callback function, crafting the replacement string and substituting the original element content with the newly defined text. Hope it helps.

    <?php
    
    $replacement = "NEW TEXT";
    $htmlContent = '
    <p data-edit="1">TEXT A</p>
    <div data-edit="2">TEXT B</div>
    ';
    
    $targetNumber = 1;
    
    $pattern = '/(<(p|div|any other tag)[^>]*data-edit="s*' . preg_quote($targetNumber, '/') . 's*"[^>]*>)(.*?)(</2>)/i';
    
    $newContent = preg_replace_callback($pattern, function ($matches) use ($replacement) {
        return $matches[1] . $replacement . $matches[4];
    }, $htmlContent);
    
    // Output the new content
    echo $newContent;
    ?>
    
    Login or Signup to reply.
  2. Regular expressions are not reliable tools for parsing HTML. It is best practice to leverage a legitimate HTML parser. In this case, I find a combination of DomDocument and XPath to be a very direct approach. Because your HTML doesn’t have a (expected) parent element, I’ll manually add a parent div tag and then removed it when stringifying the result.

    The XPath query says at any depth in the document (//), match any element (*) with the attribute data-edit ([@data-edit]). To target a specific data-edit value, write like //*[@data-edit=2].

    Code: (Demo)

    $replacement = 'NEW TEXT';
    $html = <<<HTML
    <p data-edit="1">TEXT A</p>
    <div not-data-edit="3">TEXT C</div>
    <div data-edit="2">TEXT B</div>
    HTML;
    
    $dom = new DOMDocument; 
    $dom->loadHTML('<div>' . $html . '</div>', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $xpath = new DOMXPath($dom);
    foreach ($xpath->query("//*[@data-edit]") as $node) {
        $node->nodeValue = $replacement;
    }
    var_export(substr($dom->saveHTML() ,5, -7));
    

    Notice in my demo that the code perfectly differentiates between qualified/disqualified data-edit attributes.

    '<p data-edit="1">NEW TEXT</p>
    <div not-data-edit="3">TEXT C</div>
    <div data-edit="2">NEW TEXT</div>'
    

    Regex has to go to greater effort to safeguard against fringe cases.

    Here is a somewhat related answer with similar insights: preg_replace img src to data-src stack overflow (PHP)


    More specifically about designating a data-edit number in the query, write as the following for 2. Demo

    $replacement = 'NEW TEXT';
    $dataEditNumber = 2;
    $html = <<<HTML
    <p data-edit="1">TEXT A</p>
    <div not-data-edit="2">TEXT C</div>
    <div data-edit="2">TEXT B</div>
    HTML;
    
    $dom = new DOMDocument; 
    $dom->loadHTML('<div>' . $html . '</div>', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $xpath = new DOMXPath($dom);
    foreach ($xpath->query("//*[@data-edit=$dataEditNumber]") as $node) {
        $node->nodeValue = $replacement;
    }
    var_export(substr($dom->saveHTML() ,5, -7));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search