【问题标题】:RegEx expression to find a href links and add NoFollow to them正则表达式查找一个 href 链接并将 NoFollow 添加到它们
【发布时间】:2010-03-15 22:42:45
【问题描述】:

我正在尝试编写 RegEx 规则来查找我网页上的所有 href HTML 链接,并向它们添加“rel="nofollow"”。

但是,我有一个必须排除的 URL 列表(例如,任何(通配符)内部链接(例如 pokerdiy.com) - 以便将包含我的域名的任何内部链接排除在外。我也希望能够在排除列表中指定确切的 URL - 例如 - http://www.example.com/link.aspx)

这是我目前没有工作的:

(]+)(href="http://.*?(?!(pokerdiy))[^>]+>)

如果您需要更多背景/信息,您可以在此处查看完整的线程和要求(跳过顶部直接进入正文): http://www.snapsis.com/Support/tabid/601/aff/9/aft/13117/afv/topic/afpgj/1/Default.aspx#14737

【问题讨论】:

  • 好的,我已经阅读了附件并明白了这一点。但是,我的要求是有限的,使用 RegEx 进行解析是我唯一的选择。我很欣赏以下几点: * 这通常是个坏主意。 (来自编码恐怖)。所以......考虑到这一点 - 任何人都可以帮助我的 RegEx 代码吗?我可以解释为什么我以后只限于正则表达式解析,但我需要一个解决方案,不管它看起来多么糟糕。
  • 这在这里并不真正适用,href 参数足够简单,可以被正则表达式解析,尤其是当它是所有可能的 href 的有限子集时,即只有页面中的 href!

标签: regex


【解决方案1】:

对 James 正则表达式的改进:

(<a\s*(?!.*\brel=)[^>]*)(href="https?://)((?!(?:(?:www\.)?'.implode('|(?:www\.)?', $follow_list).'))[^"]+)"((?!.*\brel=)[^>]*)(?:[^>]*)>

此正则表达式将匹配不在字符串数组 $follow_list 中的链接。字符串不需要前导“www”。 :) 优点是这个正则表达式将保留标签中的其他参数(如目标、样式、标题...)。如果标签中已经存在rel 参数,则正则表达式将不匹配,因此您可以强制关注不在 $follow_list 中的网址

替换为:

$1$2$3"$4 rel="nofollow">

完整示例(PHP):

function dont_follow_links( $html ) {
 // follow these websites only!
 $follow_list = array(
  'google.com',
  'mypage.com',
  'otherpage.com',
 );
 return preg_replace(
  '%(<a\s*(?!.*\brel=)[^>]*)(href="https?://)((?!(?:(?:www\.)?'.implode('|(?:www\.)?', $follow_list).'))[^"]+)"((?!.*\brel=)[^>]*)(?:[^>]*)>%',
  '$1$2$3"$4 rel="nofollow">',
  $html);
}

如果你想覆盖 rel 无论如何,我会使用 preg_replace_callback 方法,在回调中单独替换 rel 属性:

$subject = preg_replace_callback('%(<a\s*[^>]*href="https?://(?:(?!(?:(?:www\.)?'.implode('|(?:www\.)?', $follow_list).'))[^"]+)"[^>]*)>%', function($m) {
    return preg_replace('%\srel\s*=\s*(["\'])(?:(?!\1).)*\1(\s|$)%', ' ', $m[1]).' rel="nofollow">';
}, $subject);

【讨论】:

  • @para 如果我想阻止用户添加他自己的rel 属性怎么办?我需要阻止$follow_list中未列出的链接
  • @alex 我可能会选择 preg_replace_callback 方法作为最简单的解决方案。我相应地更新了我的答案
【解决方案2】:

我开发了一个更强大的版本,可以检测锚标记是否已经包含“rel=”,因此不会重复属性。

(<a\s*(?!.*\brel=)[^>]*)(href="https?://)((?!blog.bandit.co.nz)[^"]+)"([^>]*)>

匹配

<a href="http://google.com">Google</a>
<a title="Google" href="http://google.com">Google</a>
<a target="_blank" href="http://google.com">Google</a>
<a href="http://google.com" title="Google" target="_blank">Google</a>

但不匹配

<a rel="nofollow" href="http://google.com">Google</a>
<a href="http://google.com" rel="nofollow">Google</a>
<a href="http://google.com" rel="nofollow" title="Google" target="_blank">Google</a>
<a href="http://google.com" title="Google" target="_blank" rel="nofollow">Google</a>
<a href="http://google.com" title="Google" rel="nofollow" target="_blank">Google</a>
<a target="_blank" href="http://blog.bandit.co.nz">Bandit</a>

替换使用

$1$2$3"$4 rel="nofollow">

希望这对某人有所帮助!

詹姆斯

【讨论】:

    【解决方案3】:
    (<a href="https?://)((?:(?!\b(pokerdiy.com|www\.example\.com/link\.aspx)\b)[^"])+)"
    

    将匹配以http://https:// 开头且在href 属性中的任何位置均不包含pokerdiy.comwww.example.com/link.aspx 的任何链接的第一部分。替换为

    \1\2" rel="nofollow"
    

    如果rel="nofollow" 已经存在,您将得到其中两个。当然,相对链接或其他协议(如ftp:// 等)根本不会匹配。

    解释:

    (?!\b(foo|bar)\b)[^"] 匹配任何非" 字符,除非在当前位置可以匹配foobar\bs 用于确保我们不会意外触发 rebarfoonly

    整个结构被重复((?: ... )+),任何匹配的都保存在反向引用\2中。

    由于要匹配的下一个标记是",因此如果属性在任何地方包含foobar,则整个正则表达式都会失败。

    【讨论】:

    • Tim:这个社区的质量和乐于助人总是让我感到惊讶 - 非常感谢您的深入回答!有一个小问题 - 如果 a 链接有一个标题标签(或其他东西) - 在 a 和 href 之间,那么这个表达式会失败 - 例如。一个 target="_blank" href="casinogamblingweb.com" 将不匹配。你能帮我做吗,以便a和href之间可以有任何东西?另外 - 我了解潜在的重复 nofollow 标签。无论如何都要让表达式检查它是否已经在它的任何地方有一个 nofollow 标记?谢谢!!
    • 这应该可行,这正是我自己建议的。
    猜你喜欢
    • 2012-12-01
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多