我编写了一个用于搜索特定关键字的正则表达式,我正在用特定的URL替换该关键字。
我目前的正则表达式为:\b$keyword\b
这样做的一个问题是,如果我的数据包含锚标记,并且该标记包含此关键字,则此正则表达式也会替换锚标记中的该关键字。
我想搜索除锚标记之外的给定数据。请帮帮我。感谢您的帮助。
例如。关键词:迪士尼
I / P:
This is <a href="/test.php"> Disney </a> The disney should be replaceable
预期的O / p:
This is <a href="/test.php"> Disney </a> The <a href="any-url.php">disney</a> should be replaceable
无效的o / p:
This is <a href="/test.php"> <a href="any-url.php">Disney</a> </a> The <a href="any-url.php">disney</a> should be replaceable
答案 0 :(得分:2)
我已经修改了我的功能,突出显示了页面上的搜索短语,在这里:
$html = 'This is <a href="/test.php"> Disney </a> The disney should be replaceable.'.PHP_EOL;
$html .= 'Let\'s test also use of keyword inside other tags, for example as class name:'.PHP_EOL;
$html .= '<b class=disney></b> - this should not be replaced with link, and it isn\'t!'.PHP_EOL;
$result = ReplaceKeywordWithLink($html, "disney", "any-url.php");
echo nl2br(htmlspecialchars($result));
function ReplaceKeywordWithLink($html, $keyword, $link)
{
if (strpos($html, "<") !== false) {
$id = 0;
$unique_array = array();
// Hide existing anchor tags with some unique string.
preg_match_all("#<a[^<>]*>[\s\S]*?</a>#i", $html, $matches);
foreach ($matches[0] as $tag) {
$id++;
$unique_string = "@@@@@$id@@@@@";
$unique_array[$unique_string] = $tag;
$html = str_replace($tag, $unique_string, $html);
}
// Hide all tags by replacing with some unique string.
preg_match_all("#<[^<>]+>#", $html, $matches);
foreach ($matches[0] as $tag) {
$id++;
$unique_string = "@@@@@$id@@@@@";
$unique_array[$unique_string] = $tag;
$html = str_replace($tag, $unique_string, $html);
}
}
// Then we replace the keyword with link.
$keyword = preg_quote($keyword);
assert(strpos($keyword, '$') === false);
$html = preg_replace('#(\b)('.$keyword.')(\b)#i', '$1<a href="'.$link.'">$2</a>$3', $html);
// We get back all the tags by replacing unique strings with their corresponding tag.
if (isset($unique_array)) {
foreach ($unique_array as $unique_string => $tag) {
$html = str_replace($unique_string, $tag, $html);
}
}
return $html;
}
结果:
This is <a href="/test.php"> Disney </a> The <a href="any-url.php">disney</a> should be replaceable.
Let's test also use of keyword inside other tags, for example as class name:
<b class=disney></b> - this should not be replaced with link, and it isn't!
答案 1 :(得分:1)
将其添加到正则表达式的末尾:
(?=[^<]*(?:<(?!/?a\b)[^<]*)*(?:<a\b|\z))
此lookahead尝试匹配下一个开始<a>
标记或输入结尾,但前提是它首先看不到结束</a>
标记。假设HTML格式最小,只要匹配在<a>
标记开始后和相应的</a>
标记之前开始,前瞻就会失败。
为防止它在任何其他标记内(例如<div class="disney">
)匹配,您也可以添加此前瞻:
(?![^<>]*+>)
有了这个,我假设标签的属性值中没有任何尖括号,根据HTML 4规范是合法的,但在现实世界中极为罕见。
如果您正在以PHP双引号字符串的形式编写正则表达式(如果您希望替换$keyword
变量,则必须使用它),您应该将所有反斜杠加倍。 \z
可能不是问题,但我相信\b
会被解释为退格,而不是字边界断言。
编辑:第二个想法,肯定会添加第二个前瞻 - 我的意思是,为什么不想要阻止标记内的匹配?并将其放在第一位,因为它会比另一种更快地评估:
(?![^<>]*+>)(?=[^<]*(?:<(?!/?a\b)[^<]*)*(?:<a\b|\z))
答案 2 :(得分:0)
首先剥离标签,然后搜索剥离的文本。