replace html标签,忽略preg_replace中的html标签

小编典典

我假设您应该基于DOMDocument和DOMXPath而不是使用正则表达式来创建函数。即使那些功能非常强大,您也会遇到像您描述的问题那样的问题,这些问题不是(总是)很容易且不易用正则表达式解决的。

俗话说:不要用正则表达式解析HTML。

记住这是一个好规则,尽管与任何规则一样,它并不总是适用,值得对此下定决心。

XPath允许您查找所有仅包含文本中搜索词的文本,而忽略所有XML元素。

然后,您只需要将这些文本包装到中就可以了。

编辑: 最后一些代码;)

首先,它利用xpath来定位包含搜索文本的元素。我的查询看起来像这样,这可能写得更好,我不是超级xpath专业人士:

'//*[contains(., "'.$search.'")]/*[FALSE = contains(., "'.$search.'")]/..'

$search包含要搜索的文本, 不

包含任何"(双引号)字符(这会破坏它,如果需要引号。

该查询将返回所有包含textnode的父级,这些node在一起将是一个包含您搜索词的字符串。

由于这样的列表不容易按原样进行进一步处理,因此我创建了一个TextRange表示DOMText节点列表的类。对textnode列表进行字符串操作就像将它们当作一个字符串一样有用。

这是例程的基本框架:

$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);

}

}

}

对于我的示例XML:

This is some text that span across a page to search in.

and more text that span

它产生以下结果:

This is some text that span across a page to search in.

and more text that span

这表明,这甚至允许查找分布在多个标签中的文本。使用正则表达式根本不是那么容易。

您可以在此处找到完整的代码:(包括TextRange我从答案示例中摘录的类)。

由于该站点正在使用较旧的LIBXML版本,因此无法在viper键盘上正常工作。它对于我的LIBXML版本20707正常工作。我创建了一个与此问题相关的问题:XPath查询结果顺序。

警告提示:

本示例使用二进制字符串搜索(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'))

2020-05-10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值