我有一个包含html代码的表单,由于MCE编辑器的自动格式化无法禁用,因此偶尔会有点乱。
我已经用PHP进行了一些简单的替换,但是其他一些我不太确定。
删除所有 <span>
代码,例如<span style="font-family: inherit; font-weight: inherit; line-height: 1.3;">
,包括</span>
对应代码,但不这些代码内容。< / p>
例如:<span style="font-family: inherit; font-weight: inherit; line-height: 1.3;">StackOverflow</span>
会变成 StackOverflow
唯一应该删除 NOT 的是以下内容:
<span class="MainLink" style="font-weight: bold"><a href="https://website.com/" style="color: #2f82de; text-decoration: none">link name</a></span>
所以基本上任何封装<a href...
链接。
任何想法如何做到这一点,我认为我需要使用正则表达式来做,但可能有一个更容易/更好的方法。
答案 0 :(得分:2)
要执行此操作,您需要一个Parser,而不是正则表达式(另请参阅The Famous Answer)
从此示例开始,使用DOMDocument
和DOMXpath
:
$dom = new DOMDocument();
libxml_use_internal_errors(1);
$dom->formatOutput = True;
$dom->loadHTML( $html );
$xpath = new DOMXPath( $dom );
while( $node = $xpath->query( '//span[not(contains(@class,"MainLink"))]' )->item(0) )
{
$fragment = $dom->createDocumentFragment();
while( $node->childNodes->length )
{
$fragment->appendChild( $node->childNodes->item(0) );
}
$node->parentNode->replaceChild( $fragment, $node );
}
echo $dom->saveHTML();
这一行:
while( $node = $xpath->query( '//span[not(contains(@class,"leave"))]' )->item(0) )
在<span>
属性中搜索不包含“leave”的每个class
节点:如果找到此模式,则执行循环(->item(0)
)。
然后您创建一个新的DOMDocumentFragment
,一个特殊的临时节点,您可以在其中添加所有子节点:
while( $node->childNodes->length )
{
$fragment->appendChild( $node->childNodes->item(0) );
}
将所有节点子节点移动到新片段后,将空<span>
节点替换为片段。
可以帮助您的其他有用的XPath:
//span[not(a)]
:选择所有<span>
节点后面没有<a>
子节点; //span[not(contains(@class,"leave")) and not(contains(@class,"yes"))]
:选择<span>
属性中没有“离开”或“是”的所有class
节点。答案 1 :(得分:1)
试试这个:
$output = preg_replace('/<span[^>]*>(?!<a[ >])|(?<!\/a>)<\/span>/', '', $input);
这个正则表达式有 两部分 :
<span>
的任何<a
。</span>
的任何/a>
。 注意:此解决方案是对问题的快速解决方案,并假定有效的HTML。可能会出现一些无法正常运行的情况,但OP可能没有任何这些情况(例如a
内的自动关闭span
标记。有关 占用的方案的演示,请参阅Regex101。
答案 2 :(得分:1)
编辑以切换捕获组
我总觉得做这样的事情真的很棘手,因为往往有很多不可预见的案件可能需要处理,或者他们会回来咬我。
话虽这么说,这种正则表达式的挑战通常很有趣。
我可能会尝试这样的事情:
(?:<span[^>]*?>)(?!<a)(.*?)(?:<\/span>)
在此处采取行动:https://regex101.com/r/qY8pL5/3
它的作用是首先尝试匹配span标记的开头,并找到开始标记最有可能结束的位置。这被放入非捕获组中,因此可以将其丢弃。接下来,它确保接下来的两个字符不是锚标记,因为不应剥离包裹锚的范围。下一部分是一个捕获组,它尽可能懒惰地抓住每个角色,直到它达到一个结束范围标记。结束范围标记也收集在非捕获组中,因此可以将其丢弃。
这将匹配包含在锚点中的独立span标记和span标记。它不会匹配包装锚点的span标签。
在php中你会像这样实现它:
$final_string = preg_replace('/(?:<span[^>]*?>)(?!<a)(.*?)(?:<\/span>)/', '${1}', $string);
第一个参数是我们的正则表达式,第二个是我们想要用来代替正则表达式匹配的东西 - 在这种情况下,第一个(在这种情况下只有)捕获组被保留 - 最后我们传递字符串我们希望与之匹敌。
请注意@ fusion3k是迄今为止编写的最佳答案,而不是为进行任何真正的HTML解析提供全面的方法。