自动将关键字转换为php中的链接

时间:2012-03-29 16:58:18

标签: php regex

我正在尝试将存储在数组中的文本中的特定关键字转换为链接。

示例文字:

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

3 个答案:

答案 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 lookbehindbackreferences

<小时/> 编辑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>

在上面的例子中,即使它符合所有其他可能的标准(它是最容易测试的空间之前和之后的空间),它仍然会导致链接中的链接,我认为打破了互联网。

因此,您需要使用lookaheadslookbehinds来检查关键字是否包含在链接中。但有一个问题:外观必须有一个定义的模式(意味着没有外卡)。

我以为自己会成为英雄,并向您展示您的问题的简单解决方案,这将起到以下作用:

'/(?<!\<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);