preg_replace字符串中的多个字段

时间:2017-10-18 10:05:38

标签: php regex

我有一个包含多个部分的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-clientdata-id

我做了什么

&#13;
&#13;
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;
&#13;
&#13;

这样做有效,但我不是非常喜欢str_replace方法,有没有办法在(单个)preg_replace中执行此操作,可能不会使用foreach?

任何暗示都赞赏!

2 个答案:

答案 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;

demo