替换与给定域不匹配的链接中的协议

Posted

技术标签:

【中文标题】替换与给定域不匹配的链接中的协议【英文标题】:Replace protocol in links that don't match a given domain 【发布时间】:2013-09-24 11:29:36 【问题描述】:

当给定的域不匹配时,我被困在仅替换文本中的链接协议的地方:

测试用例:

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam <a title="mytitle" href="https://www.other-domain.de/path/index.html" target="_blank">other domain</a> nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd <a title="other title" href="https://www.my-domain.de/path/index.html" target="_blank">my domain</a>, no sea takimata <a title="mytitle" href="https://www.other-domain.de/path2/index2.html" target="_blank">other domain</a> est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed <a title="other title" href="https://www.my-domain.de/path/index.html" target="_blank">my domain</a> voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

到目前为止的正则表达式:

$content = preg_replace('/<a (.*?)href=[\"\'](.*?)\/\/(.*?)[\"\'](.*?)>(.*?)<\/a>/i', '<a href="http://$3">$5</a>', $content);

但是,这匹配所有链接——我的目标是仅将替换应用于与给定域不匹配的链接,例如在我的情况下为“my-domain.de”。

也就是说——只有与给定域不匹配的链接才应将其协议从“https”更改为“http”。

干杯 马立克

【问题讨论】:

不要使用正则表达式解析 HTML。使用适当的 HTML 解析模块。 您无法使用正则表达式可靠地解析 HTML,并且您将面临悲伤和挫败感。一旦 HTML 与您的期望发生变化,您的代码就会被破坏。请参阅htmlparsing.com/php 或this SO thread,了解如何使用已经编写、测试和调试过的 PHP 模块正确解析 HTML。 嗨,Lester,我不想解析内容,我只需要替换一些东西。这就像获取文本、替换、放回文本一样。 正在要求解析 HTML。 如果您正在尝试查找 HTML 结构的某些部分,那么您正在解析。您可能试图通过使用正则表达式来伪装它,但您仍在解析,而正则表达式无法胜任这项任务。在这里查看原因:htmlparsing.com/regexes 那么给我一个更好的解决方案 - 顺便说一句:这发生在 Wordpress 模块中,我需要在文本中用 http 替换 https - 并将其返回给 wordpress。对我来说,不需要构建额外的 php html 解析器模块 我在原始评论中为您提供了两个页面的链接,这些页面具有更好的解决方案。 【参考方案1】:

对于它的价值,这是您正在寻找的正则表达式:

原始匹配模式:

<a ((?:(?!href).)*?)href=[\"\']https:\/\/((?:(?!my-domain.de).)*?)[\"\'](.*?)>(.*?)<\/a>

原始替换模式:

<a $1href="http://$2"$3>$4</a>

PHP代码为:

$content = preg_replace('/<a ((?:(?!href).)*?)href=[\"\']https:\/\/((?:(?!my-domain.de).)*?)[\"\'](.*?)>(.*?)<\/a>/i','<a $1href="http://$2"$3>$4</a>',$content);

话虽如此,但请注意——就Andy Lester 而言,这个正则表达式并不可靠。 虽然在我看来,问题并不完全是“HTML 的本质”,或者至少不那么简单。这个公认的伟大资源——http://htmlparsing.com/regexes——的重点是,你正试图在一条非常崎岖的道路上重新发明***。更广泛的关注是“并不是正则表达式本身是邪恶的,而是过度使用正则表达式是邪恶的。”这句话来自杰夫·阿特伍德,来自一个特殊的阐述关于正则表达式的乐趣和恐惧在这里:Regular Expressions: Now You Have Two Problems(他还有一篇文章专门警告不要使用正则表达式解析 HTML——Parsing Html The Cthulhu Way。)

特别是在我上面的“解决方案”的情况下,例如——以下输入(带有行返回)将不匹配,尽管是有效的 HTML:

<a title="mytitle"
href="https://www.other-domain.de/path/index.html" 
target="_blank">other domain</a>

但是,以下输入将根据需要进行处理:

<a href="https://my-domain.de">my domain</a>
<a href="https://other-domain.de">other domain</a>

<a href="https://www.my-domain.de/path/index.html">my domain</a>
<a href="https://www.other-domain.de/path/index.html">other domain</a>

<a title="other title" href="https://www.my-domain.de/path/index.html" target="_blank">other domain</a>
<a title="my title" href="https://www.other-domain.de/path/index.html" target="_blank">my domain</a>

变成:

<a href="https://my-domain.de">my domain</a>
<a href="http://other-domain.de">other domain</a>

<a href="https://www.my-domain.de/path/index.html">my domain</a>
<a href="http://www.other-domain.de/path/index.html">other domain</a>

<a title="other title" href="https://www.my-domain.de/path/index.html" target="_blank">other domain</a>
<a title="my title" href="http://www.other-domain.de/path/index.html" target="_blank">my domain</a>

这里有一个很好的资源来解释正则表达式的完整分解:http://www.myregextester.com/index.php

要在该工具上复制测试:

选择“替换”操作 将您的正则表达式放入“匹配模式” 将替换放入“替换模式” 选中“i”标志复选框 选中“解释”复选框 选中“PHP”复选框 将您的目标内容放入“源文本”中 点击“提交”

为了方便和后代,我在下面包含了该工具提供的完整说明,但其中两个概念性亮点是:

前瞻和负前瞻——例如(?!text)http://php.net/manual/en/regexp.reference.assertions.php

非捕获子模式——例如(?:text)(?:(?!text))的外部http://php.net/manual/en/regexp.reference.subpatterns.php

匹配模式说明:

The regular expression:

`(?i-msx:<a ((?:(?!href).)*?)href=[\"\']https:\/\/((?:(?!my-domain.de).)*?)[\"\'](.*?)>(.*?)<\/a>)`

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?i-msx:                 group, but do not capture (case-insensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  <a                       '<a '
----------------------------------------------------------------------
  (                        group and capture to \1:
----------------------------------------------------------------------
    (?:                      group, but do not capture (0 or more
                             times (matching the least amount
                             possible)):
----------------------------------------------------------------------
      (?!                      look ahead to see if there is not:
----------------------------------------------------------------------
        href                     'href'
----------------------------------------------------------------------
      )                        end of look-ahead
----------------------------------------------------------------------
      .                        any character except \n
----------------------------------------------------------------------
    )*?                      end of grouping
----------------------------------------------------------------------
  )                        end of \1
----------------------------------------------------------------------
  href=                    'href='
----------------------------------------------------------------------
  [\"\']                   any character of: '\"', '\''
----------------------------------------------------------------------
  https:                   'https:'
----------------------------------------------------------------------
  \/                       '/'
----------------------------------------------------------------------
  \/                       '/'
----------------------------------------------------------------------
  (                        group and capture to \2:
----------------------------------------------------------------------
    (?:                      group, but do not capture (0 or more
                             times (matching the least amount
                             possible)):
----------------------------------------------------------------------
      (?!                      look ahead to see if there is not:
----------------------------------------------------------------------
        my-domain                'my-domain'
----------------------------------------------------------------------
        .                        any character except \n
----------------------------------------------------------------------
        de                       'de'
----------------------------------------------------------------------
      )                        end of look-ahead
----------------------------------------------------------------------
      .                        any character except \n
----------------------------------------------------------------------
    )*?                      end of grouping
----------------------------------------------------------------------
  )                        end of \2
----------------------------------------------------------------------
  [\"\']                   any character of: '\"', '\''
----------------------------------------------------------------------
  (                        group and capture to \3:
----------------------------------------------------------------------
    .*?                      any character except \n (0 or more times
                             (matching the least amount possible))
----------------------------------------------------------------------
  )                        end of \3
----------------------------------------------------------------------
  >                        '>'
----------------------------------------------------------------------
  (                        group and capture to \4:
----------------------------------------------------------------------
    .*?                      any character except \n (0 or more times
                             (matching the least amount possible))
----------------------------------------------------------------------
  )                        end of \4
----------------------------------------------------------------------
  <                        '<'
----------------------------------------------------------------------
  \/                       '/'
----------------------------------------------------------------------
  a>                       'a>'
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

【讨论】:

PS:一个更漂亮的正则表达式工具可以在这里找到,永久链接到解决方案加上原始输入示例 -- regex101.com/r/xE8eP4

以上是关于替换与给定域不匹配的链接中的协议的主要内容,如果未能解决你的问题,请参考以下文章

如果用户名/电子邮件与特定域不匹配,则显示窗口警报

MySQL替换给定域的.html链接

如何在由cmake生成的链接命令行中用-Ldir2替换给定的-Ldir1

PHP正则匹配与替换的简单例子

[HDOJ5763]Another Meaning(KMP, DP)

如何使用 MySQL 连接语句选择与链接表中的多个值匹配的记录?