我正在尝试将存储在数组中的文本中的特定关键字转换为链接。
示例文字:
$text='This text contains many keywords, but also formated <a href="#keywords" title="keywords">keywords</a>.'
现在我想将关键字转换为<a href="#keywords" title="keywords">#keywords</a>
。
我使用了非常简单的preg_replace函数
preg_replace('/keywords/i',' <a href="#keywords">keywords</a> ',$text);
但显然它转换为链接也将字符串已经格式化为链接,因此我得到一个凌乱的HTML:
$text='This text contains many <a href="#keywords" title="keywords">keywords</a>, but also formated <a href="#<a href="#keywords" title="keywords">keywords</a>" title="<a href="#keywords" title="keywords">keywords</a>"><a href="#keywords" title="keywords">keywords</a></a>.'
预期结果:
$text='This text contains many <a href="#keywords" title="keywords">keywords</a>, but also formated <a href="#keywords" title="keywords">keywords</a>.'
有什么建议吗? THX
修改
我们距离完美功能只有一步,但在这种情况下仍然不能正常运作:
$text='This text contains many keywords, but also formated
<a href="http://www.keywords.com/keywords" title="keywords">keywords</a>.'
在这种情况下,它还会替换href中的单词keywords
,所以我们再次得到像
<a href="http://www.<a href="http://www.keywords.com/keywords" title="keywords">keywords</a>.com/<a href="http://www.keywords.com/keywords" title="keywords">keywords</a>" title="keywords">keywords</a>
答案 0 :(得分:2)
我对正则表达式不太满意,但也许这个会起作用:
/[^#>"]keywords/i
我认为它会忽略#keywords
,>keywords
和"keywords
的所有实例并找到其余的。
<小时/> 的修改:
在测试之后,它看起来也替换了单词之前的空格,如果keywords
是字符串的开头,则不起作用。它也没有保留原始资本化。我测试了这个,它对我来说很有效:
$string = "Keywords and keywords, plus some more keywords with the original <a href=\"#keywords\" title=\"keywords\">keywords</a>.";
$string = preg_replace("/(?<![#>\"])keywords/i", "<a href=\"#keywords\">$0</a>", $string);
echo $string;
前三个被替换,保留原始大写,最后一个未被触及。这个使用negative lookbehind和backreferences。
<小时/> 编辑2:
OP编辑的问题。提供新示例后,以下正则表达式将起作用:
$string = 'This text contains many keywords, but also formated <a href="http://www.keywords.com/keywords" title="keywords">keywords</a>.';
$string = preg_replace("/(?<![#>\".\/])keywords/i", "<a href=\"http://www.keywords.com/keywords\" title=\"keywords\">$0</a>", $string);
echo $string;
// outputs: This text contains many <a href="http://www.keywords.com/keywords" title="keywords">keywords</a>, but also formated <a href="http://www.keywords.com/keywords" title="keywords">keywords</a>.
这将替换keywords
,#
,>
,"
或.
之前没有/
的所有实例。
答案 1 :(得分:1)
问题在于:
关键字可以位于链接的href,标题或文本中,也可以位于其中的任何位置(例如关键字是sanity
并且您已经拥有href="insanity"
。或者更糟糕的是,您可以拥有一个恰好包含关键字的非关键字链接,例如:
<a href="http://example.org/">Click here to find more keywords and such!</a>
在上面的例子中,即使它符合所有其他可能的标准(它是最容易测试的空间之前和之后的空间),它仍然会导致链接中的链接,我认为打破了互联网。
因此,您需要使用lookaheads
和lookbehinds
来检查关键字是否包含在链接中。但有一个问题:外观必须有一个定义的模式(意味着没有外卡)。
我以为自己会成为英雄,并向您展示您的问题的简单解决方案,这将起到以下作用:
'/(?<!\<a.?>)[list|of|keywords](?!\<\/a>)/'
除非你不能这样做,因为在这种情况下,lookbehind具有该通配符。没有它,你最终会得到一个超级贪婪的表达。
所以我建议的替代方法是使用正则表达式来查找所有链接元素,然后使用str_replace
将它们与占位符交换出来,然后将它们替换为末尾的占位符。
我是这样做的:
$text='This text contains many keywords, but also formated <a href="#keywords" title="keywords">keywords</a>.';
$keywords = array('text', 'formatted', 'keywords');
//This is just to make the regex easier
$keyword_list_pattern = '['. implode($keywords,"|") .']';
// First, get all matching keywords that are inside link elements
preg_match_all('/<a.*' . $keyword_list_pattern . '.*<\/a>/', $text, $links);
$links = array_unique($links[0]); // Cleaning up array for next step.
// Second, swap out all matches with a placeholder, and build restore array:
foreach($links as $count => $link) {
$link_key = "xxx_{$count}_xxx";
$restore_links[$link_key] = $link;
$text = str_replace($link, $link_key, $text);
}
// Third, we build a nice replacement array for the keywords:
foreach($keywords as $keyword) {
$keyword_links[$keyword] = "<a href='#$keyword'>$keyword</a>";
}
// Merge the restore links to the bottom of the keyword links for one mass replacement:
$keyword_links = array_merge($keyword_links, $restore_links);
$text = str_replace(array_keys($keyword_links), $keyword_links, $text);
echo $text;
答案 2 :(得分:0)
您可以更改RegEx,使其仅定位到前面有空格的关键字。由于格式化的关键字不包含空格。这是一个例子。
$text = preg_replace('/ keywords/i',' <a href="#keywords">keywords</a>',$text);