preg_replace正则表达式更改标记内的特定符号

时间:2011-07-15 15:09:42

标签: regex preg-replace

我有一个 span 元素,里面有一些文字。 有时,此元素的内容也包括其他元素(标记)。

例如:

<span id="span_id"><a href="http://someurl" title="sometitle">value</a></span>

我需要做的是转换所有'&lt;'在范围内到“〜lt〜”和所有“&gt;”到“~gt~”。 可能存在层次结构,例如在 a 元素中可能有 img 标记等。

所以如果输入是:

<span id="span_id"><a href="http://someurl" title="sometitle"><img src="http://anotherurl"/></a></span>

输出应为:

<span id="span_id">~lt~a href="http://someurl" title="sometitle"~gt~~lt~img src="http://anotherurl"/~gt~~lt~/a~gt~</span>

谢谢!

UPD 我从这里采取了解决方案PHP: using preg_replace with htmlentities

1 个答案:

答案 0 :(得分:0)

正如其他人所说,你需要接受你所提问题的答案。

这是一个使用preg_replace_callback()函数的解决方案。主正则表达式匹配“最里面的”SPAN元素(但请参阅下面的CAVEAT)。回调函数处理元素内容,用<替换每个&lt;,用>替换每个&gt;

function escapeSpanContents($text) {
    return preg_replace_callback('%
        # Match an innermost SPAN element.
        (<span\b[^>]*>)   # $1: SPAN element start tag.
        (                 # $2: SPAN element contents.
          [^<]*           # Non-start or end tag < chars. {normal*}
          (?:             # Begin {(special normal*)*} construct.
            <             # {special} is any < that is...
            (?!/?span\b)  # neither a <span or </span
            [^<]*         # More {normal*}
          )*              # Finish "Unrolling-the-Loop"
        )                 # End $2: SPAN element contents.
        (</span\s*>)      # $3: SPAN element end tag.
        %sx', '_escapeSpanContentsCallback', $text);
}
function _escapeSpanContentsCallback($matches) {
    $matches[2] = str_replace(
        array('<', '>'),
        array('&lt;', '&gt;'),
        $matches[2]);
    return $matches[1] . $matches[2] . $matches[3];
}

CAVEATS:这将无法匹配包含尖括号的开始标记属性的SPAN元素(应该很少见)。它还会错误地匹配出现在COMMENT,SCRIPT和STYLE元素中的SPAN“元素”。虽然这个解决方案可以做得相当不错,但如果你需要100%可靠的结果,最好使用HTML解析器。