Fab*_*geb 5 html php preg-replace
如何忽略此preg_replace中的html标记.我有搜索的foreach函数,所以如果有人搜索"apple span",preg_replace也会对span和html中断应用跨度:
preg_replace("/($keyword)/i","<span class=\"search_hightlight\">$1</span>",$str);
Run Code Online (Sandbox Code Playgroud)
提前致谢!
我认为您应该使您的函数基于 DOMDocument 和 DOMXPath 而不是使用正则表达式。即使这些功能非常强大,您也会遇到像您所描述的那样的问题,这些问题(总是)无法轻松且稳健地使用正则表达式来解决。
一般的说法是:不要用正则表达式解析 HTML。
这是一条值得牢记的好规则,尽管与任何规则一样,它并不总是适用,但值得下定决心。
XPath 允许您仅在文本中查找包含搜索词的所有文本,而忽略所有 XML 元素。
然后你只需要将这些文本包装到 中<span>就可以了。
编辑:最后一些代码;)
首先,它用于xpath定位包含搜索文本的元素。我的查询看起来像这样,这可能会写得更好,我不是超级 xpath 专业人士:
'//*[contains(., "'.$search.'")]/*[FALSE = contains(., "'.$search.'")]/..'
Run Code Online (Sandbox Code Playgroud)
$search包含要搜索的文本,不包含任何"(引号)字符(这会破坏它,如果需要引号,请参阅清理/清理 xpath 属性以获取解决方法)。
此查询将返回包含文本节点的所有父级,这些文本节点放在一起将成为包含您的搜索词的字符串。
由于这样的列表不容易按原样进一步处理,因此我创建了一个TextRange表示节点列表的类DOMText。对一系列文本节点执行字符串操作非常有用,就好像它们是一个字符串一样。
这是例程的基本框架:
$str = '...'; # some XML
$search = 'text that span';
printf("Searching for: (%d) '%s'\n", strlen($search), $search);
$doc = new DOMDocument;
$doc->loadXML($str);
$xp = new DOMXPath($doc);
$anchor = $doc->getElementsByTagName('body')->item(0);
if (!$anchor)
{
throw new Exception('Anchor element not found.');
}
// search elements that contain the search-text
$r = $xp->query('//*[contains(., "'.$search.'")]/*[FALSE = contains(., "'.$search.'")]/..', $anchor);
if (!$r)
{
throw new Exception('XPath failed.');
}
// process search results
foreach($r as $i => $node)
{
$textNodes = $xp->query('.//child::text()', $node);
// extract $search textnode ranges, create fitting nodes if necessary
$range = new TextRange($textNodes);
$ranges = array();
while(FALSE !== $start = strpos($range, $search))
{
$base = $range->split($start);
$range = $base->split(strlen($search));
$ranges[] = $base;
};
// wrap every each matching textnode
foreach($ranges as $range)
{
foreach($range->getNodes() as $node)
{
$span = $doc->createElement('span');
$span->setAttribute('class', 'search_hightlight');
$node = $node->parentNode->replaceChild($span, $node);
$span->appendChild($node);
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于我的示例 XML:
<html>
<body>
This is some <span>text</span> that span across a page to search in.
and more text that span</body>
</html>
Run Code Online (Sandbox Code Playgroud)
它产生以下结果:
<html>
<body>
This is some <span><span class="search_hightlight">text</span></span><span class="search_hightlight"> that span</span> across a page to search in.
and more <span class="search_hightlight">text that span</span></body>
</html>
Run Code Online (Sandbox Code Playgroud)
这表明这甚至允许查找分布在多个标签中的文本。对于正则表达式来说,这根本不是那么容易实现的。
您可以在这里找到完整的代码:http://codepad.viper-7.com/U4bxbe(包括TextRange我从答案示例中取出的类)。
由于该站点使用的是较旧的 LIBXML 版本,因此它无法在 viper 键盘上正常工作。它适用于我的 LIBXML 版本 20707。我创建了一个关于此问题的相关问题:XPath query result order。
警告注意事项:此示例使用二进制字符串搜索 ( strpos) 和相关偏移量来使用该DOMText::splitText函数分割文本节点。这可能会导致错误的偏移量,因为函数需要 UTF-8 字符偏移量。正确的方法是使用基值mb_strpos来获取UTF-8。
无论如何,该示例都可以工作,因为它仅使用与示例数据US-ASCII具有相同偏移量的数据。UTF-8
对于现实生活中的情况,$search字符串应该是 UTF-8 编码的,并且mb_strpos应该使用而不是strpos:
while(FALSE !== $start = mb_strpos($range, $search, 0, 'UTF-8'))
Run Code Online (Sandbox Code Playgroud)