1

Okay, so my question is pretty simple. I hope the answer is too. Let's say I have the following php string:

<!DOCTYPE html>
<html>
<head>
    <title>test file</title>
</head>
<body>
    <div id="dynamicContent">
        <myTag>PART_ONE</myTag>
        <myTag>PART_TWO </myTag>
        <myTag> PART_THREE</myTag>
        <myTag> PART_FOUR </myTag>
    </div>
</body>
</html>

Let's say this is $content. Now, you can see I have 4 custom tags (myTag) with one word content. (PART_ONE, PART_TWO, etc.) I want to replace those 4 with 4 different strings. Those latter 4 strings are in an array:

$replace = array("PartOne", "PartTwo", "PartThree", "PartFour");

I did this but it doesn't work succesfully:

$content = preg_replace("/<myTag>(.*?)<\/myTag>/s", $replace, $content);

So, I want to search for myTags (it finds 4) and replace it with one entry of the array. The first occurrence should be replaced by $replace[0], the second by $replace[1], etc. Then, it will return the "new" content as a string (not as an array) so I can use it for further parsing.

How should I realize this?

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
John Smith
  • 965
  • 1
  • 9
  • 22
  • 1
    It would be much, much simpler to search for PART_ONE etc... – Floris Mar 06 '13 at 15:41
  • 2
    http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags – TFennis Mar 06 '13 at 15:42
  • Oh yeah, I forgot to tell that I do not know the value of myTag, so PART_ONE can just as good be "MY_ELEPHANT". I should be able to enter anything in the html template and then the code will see whatever is between the myTag tags. Also, I don't think the saying "You can't parse html with regex" applies here, since I am not parsing the attributes of a tag, but just the value of a tag which is a simple and failsafe task for regex. – John Smith Mar 06 '13 at 15:45
  • You could use preg_replace_callback() instead. – Ja͢ck Mar 06 '13 at 15:57

4 Answers4

1

Something like the following should work:

$replace = array("PartOne", "PartTwo", "PartThree", "PartFour");
if (preg_match_all("/(<myTag>)(.*?)(<\/myTag>)/s", $content, $matches)) {
    for ($i = 0; $i < count($matches[0]); $i++) {
        $content = str_replace($matches[0][$i], $matches[1][$i] . $replace[$i] . $matches[3][$i], $content);
    }
}
h2ooooooo
  • 39,111
  • 8
  • 68
  • 102
0

One approach would be to loop over each element in the array you want to replace with; replace the words myTag with myDoneTag or something for each one you finished, so you find the next one. Then you can always put back myTag at the end, and you have your string:

for(ii=0; ii<4; ii++) {
    $content = preg_replace("/<myTag>.*<\/myTag>/s", "<myDoneTag>".$replace[ii]."<\/myDoneTag>", $content, 1);
}
$content = preg_replace("/myDoneTag/s", "myTag", $content);
Floris
  • 45,857
  • 6
  • 70
  • 122
  • If the regex matches it will replace everything the first time, and not care about the other 3 loop iterations. – h2ooooooo Mar 06 '13 at 15:57
  • Hmm, although I already thought something like this would be the answer and accept it, I don't think it's wise to use this since it's basically a loop within a loop (preg_replace loops too) and thus this lags performance. I guess if there's no other high performance solution I'll just go with (X)HTML parsing or something like that. – John Smith Mar 06 '13 at 15:59
  • @h2ooooooo - you are right. Added the "limit" parameter and set it to 1 - "replace only the first instance". – Floris Mar 06 '13 at 15:59
  • @JohnSmith - I believe clarity should trump speed except when performance is really at a premium. You're going around this loop four times - and the regex will stop each time it finds the first match. Do you really think you get a measurable performance penalty? – Floris Mar 06 '13 at 16:02
0

With regexes, you could something like this:

$replaces = array('foo','bar','foz','bax');
$callback = function($match) use ($replaces) {
        static $counter = 0;
        $return = $replaces[$counter % count($replaces)];
        $counter++;
        return $return;
};
var_dump(preg_replace_callback('/a/',$callback, 'a a a a a '));

But really, when searching for tags in html or xml, you want a parser:

$html = '<!DOCTYPE html>
<html>
<head>
    <title>test file</title>
</head>
<body>
    <div id="dynamicContent">
        <myTag>PART_ONE</myTag>
        <myTag>PART_TWO </myTag>
        <myTag> PART_THREE</myTag>
        <myTag> PART_FOUR </myTag>
    </div>
</body>
</html>';

$d = new DOMDocument();
$d->loadHTML($html);
$counter = 0;
foreach($d->getElementsByTagName('mytag') as $node){
        $node->nodeValue = $replaces[$counter++ % count($replaces)];
}
echo $d->saveHTML();
Wrikken
  • 69,272
  • 8
  • 97
  • 136
-2

This should be the syntax you're looking for:

$patterns = array('/PART_ONE/', '/PART_TWO/', '/PART_THREE/', '/PART_FOUR/');
$replaces = array('part one', 'part two', 'part three', 'part four');

preg_replace($patterns, $replaces, $text);

But be warned, these are run sequentially so if the text for 'PART_ONE` contains the text 'PART_TWO' that will be subsequently replaced.

Sammitch
  • 30,782
  • 7
  • 50
  • 77