how to enumerate items with preg_replace?
I need to add some tags before and after images on document and numerate them at once. HTML Document code is:
....
<img src="http://img.example.com/img/mage1.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/image72.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/imagstr.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/image.开发者_StackOverflowjpg" alt="sometile"> <br>
<img src="http://img.example.com/img/imgger.gif" alt="sometile"> <br>
<img src="http://img.example.com/img/somepic.png" alt="sometile"> <br>
I need in result code like this
<div><a name="#pic1"></a><img src="http://img.example.com/img/mage1.jpg" alt="sometile"></div>
<div><a name="#pic2"></a><img src="http://img.example.com/img/image72.jpg" alt="sometile"> </div>
<div><a name="#pic3"></a><img src="http://img.example.com/img/imagstr.jpg" alt="sometile"> </div>
<div><a name="#pic4"></a><img src="http://img.example.com/img/image.jpg" alt="sometile"> </div>
<div><a name="#pic5"></a><img src="http://img.example.com/img/imgger.gif" alt="sometile"> </div>
<div><a name="#pic6"></a><img src="http://img.example.com/img/somepic.png" alt="sometile"> </div>
As usually, you can also do that with DOM:
$counter = 0;
$doc = new DOMDocument();
$doc->loadHTML($str);
foreach ($doc->getElementsByTagName("img") as $img) {
$sibling = $img->nextSibling;
while ($sibling) {
if ($sibling instanceof DOMElement && $sibling->tagName === 'br') {
$sibling->parentNode->removeChild($sibling);
}
$sibling = $sibling->nextSibling;
}
$div = $doc->createElement("div");
$img->parentNode->replaceChild($div, $img);
$a = $doc->createElement("a");
$a->setAttribute("name", "pic" . (++$counter));
$a->appendChild($img);
$div->appendChild($a);
}
$str = '';
foreach (simplexml_import_dom($doc->getElementsByTagName("body")->item(0))->children() as $elem) {
$str .= $elem->asXML();
}
I'm not a fan of regex+HTML, but here goes (I just cooked up a simple regex—you probably already have one):
$s = '<img src="http://img.example.com/img/mage1.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/image72.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/imagstr.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/image.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/imgger.gif" alt="sometile"> <br>
<img src="http://img.example.com/img/somepic.png" alt="sometile"> <br>';
$i = 0;
function wrap($s) {
global $i;
$i++;
return sprintf('<div><a name="pic%d">%s</div>', $i, $s);
}
print preg_replace('#(<img [^>]+?>) <br>#e', "wrap('\\1')", $s);
(Demo)
The important part is the e
modifier in the preg_replace()
. See "Example #4 Using the 'e' modifier."
EDIT
As pointed out in the comments, $i
is certainly not the best name for a global variable. If this is going to be used as a simple "one-off" transformation it may be alright. If not, change the name to something that will not conflict. Or put it as a public static
in a class.
Also, preg_replace_callback()
exists. It's better suited, although I find the passing a function name as a string and evaluating functionName('arg')
almost equally ugly :)
First of all, you are not supposed to use Regexes to deal with HTML.
However, in this case it's easy as you are almost dealing with full lines:
$code = '<img src="http://img.example.com/img/mage1.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/image72.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/imagstr.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/image.jpg" alt="sometile"> <br>
<img src="http://img.example.com/img/imgger.gif" alt="sometile"> <br>
<img src="http://img.example.com/img/somepic.png" alt="sometile"> <br>';
function get_num_row($matches) {
global $last_num;
return '<div><a name="pic' . (++$last_num) . '">' . trim($matches[1]) . '</a></div>';
}
$last_num = 0;
$code = preg_replace_callback('/^(.*)<br>$/m', 'get_num_row', $code);
echo $code;
Output:
<div><a name="pic1"><img src="http://img.example.com/img/mage1.jpg" alt="sometile"></a></div>
<div><a name="pic2"><img src="http://img.example.com/img/image72.jpg" alt="sometile"></a></div>
<div><a name="pic3"><img src="http://img.example.com/img/imagstr.jpg" alt="sometile"></a></div>
<div><a name="pic4"><img src="http://img.example.com/img/image.jpg" alt="sometile"></a></div>
<div><a name="pic5"><img src="http://img.example.com/img/imgger.gif" alt="sometile"></a></div>
<div><a name="pic6"><img src="http://img.example.com/img/somepic.png" alt="sometile"></a></div>
Of course you need to set $last_num
to 0
if you are going to use the callback again.
There's no way to do it without a global or static var. But if you are going to use the callback only once ever you can simply change global $last_num;
to static $last_num = 0;
. Then it will increment forever with no chance of resetting it - but it won't clutter your global namespace.
精彩评论