我有一个包含多个部分的html字符串:
$source = '
<span id="pass_AwfpSYYUsn" data-id="AwfpSYYUsn" class="pointer unlockFieldChild" data-client="51" data-status="closed"><i class="fa fa-lock"></i> Show</span>
<!-- OTHER HTML STUFF -->
<span id="pass_DbTD7TjEDX" data-id="DbTD7TjEDX" class="pointer unlockFieldChild" data-client="51" data-status="closed"><i class="fa fa-lock"></i> Show</span>
';
我想用这个代替所有这些:
[pass id="AwfpSYYUsn"]PASSWORD OR EMPTY[/pass]
<!-- OTHER HTML STUFF -->
[pass id="DbTD7TjEDX"]PASSWORD OR EMPTY[/pass]
我需要data-client
和data-id
我做了什么
preg_match_all('@<span id="pass_(.*?)".*?data-client="(.*?)".*?</span>@', $content, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$pw = '';
/* This checks and fills the password, not really relvant to the question */
if ($aG->getCanPassword()) {
$p = $em->getRepository('AppBundle:PasswordList')->findOneBy(array(
'code' => $match[1],
));
if ($p !== null) {
$pw = $p->getPass();
}
}
$content = str_replace('<span id="pass_' . $match[1] . '" data-id="' . $match[1] . '" class="pointer unlockFieldChild" data-client="' . $match[2] . '" data-status="closed"><i class="fa fa-lock"></i> Show</span>', '[pass id="' . $match[1] . '"]' . $pw . '[/pass]', $content);
}
&#13;
这样做有效,但我不是非常喜欢str_replace
方法,有没有办法在(单个)preg_replace
中执行此操作,可能不会使用foreach?
任何暗示都赞赏!
答案 0 :(得分:0)
preg_replace究竟出现了什么问题?在替换字符串中使用$ 1,$ 2 ...来插入捕获的内容:
preg_replace('%<span id="pass_(.*?)".*?data-client="(.*?)".*?</span>%', '[pass id="$1"]PASSWORD OR EMPTY[/pass]', $subject);
答案 1 :(得分:0)
正则表达式不编辑html内容的方式。 html过于复杂,充满了陷阱以获得可信赖的结果。 PHP已经有一个基于libxml的内置html解析器:
$content = '
<span id="pass_AwfpSYYUsn" data-id="AwfpSYYUsn" class="pointer unlockFieldChild" data-client="51" data-status="closed"><i class="fa fa-lock"></i> Show</span>
<!-- OTHER HTML STUFF -->
<span id="pass_DbTD7TjEDX" data-id="DbTD7TjEDX" class="pointer unlockFieldChild" data-client="51" data-status="closed"><i class="fa fa-lock"></i> Show</span>
';
$dom = new DOMDocument;
$state = libxml_use_internal_errors(true);
$dom->loadHTML('<div id="root">' . $content . '</div>'); // add a fake root element
// (usefull if you don't work with a full html document)
$xp = new DOMXPath($dom);
$nodeList = $xp->query('//span[starts-with(@id, "pass_")]');
foreach ($nodeList as $node) {
$idpass = explode('_', $node->getAttribute('id'), 2)[1];
$pw = '';
if ($aG->getCanPassword()) {
$p = $em->getRepository('AppBundle:PasswordList')->findOneBy(['code' => $idpass]);
if ($p !== null) {
$pw = $p->getPass();
}
}
$textNode = $dom->createTextNode('[pass id="' . $idpass . '"]' . $pw . '[/pass]');
$node->parentNode->replaceChild($textNode, $node);
}
$content = '';
foreach($dom->getElementById('root')->childNodes as $childNode) {
$content .= $dom->saveHTML($childNode);
}
libxml_use_internal_errors($state);
echo $content;