我正在使用phpBB3制作留言板。内置功能可以将帖子中的所有URL和呈现作为链接。我想做到这一点,只有本地链接可以点击。
phpbb3在帖子的文本中使用正则表达式,并且对于每个匹配将其更改为链接:
if ($somestuff){
// matches a xxxx://aaaaa.bbb.cccc. ...
$magic_url_match[] = '#(^|[\n\t (>.])(' . "[a-z]$scheme*:/{2}(?:(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#ie';
$magic_url_replace[] = "make_clickable_callback(MAGIC_URL_FULL, '\$1', '\$2', '', '$class')";
// matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
$magic_url_match[] = '#(^|[\n\t (>])(' . "www\.(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#ie';
$magic_url_replace[] = "make_clickable_callback(MAGIC_URL_WWW, '\$1', '\$2', '', '$class')";
}
return preg_replace($magic_url_match, $magic_url_replace, $text);
如何重写这些正则表达式,以便它们只匹配我的域上的链接?另外,教自己正则表达式的最佳方法是什么?
答案 0 :(得分:2)
这是第一个,逐节分解。即使这样做也是非常重要的......
(
^
|
[\n\t (>.]
)
好的,这里我们只是“行的开头,或换行符,制表符,空格,大于,句号。只需锚定正则表达式。
(
[a-z]$scheme*:/{2}
这是纯粹的疯狂。 $scheme
可能会保留http
,这意味着此正则表达式与http://
匹配。为什么有人会使用/{2}
代替//
,我无法开始猜测。
(?:
(?:
[a-z0-9\-._~!$&'($inline*+,;=:@|]+
|
%[\dA-F]{2}
)+
|
这匹配了一系列字符,可能是那些在URL中合法的字符。值得注意的是$inline
PHP变量 - 不能猜测它的含义 - 以及第二个替代%[\dA-F]{2}
。对于空格等匹配%20
之类的内容等。%
符号在匹配(或URL)中不合法。
此处同样重要的是/
不合法。因此,这不能引用目录,只能引用域。这很可能是您想要更改的部分,只需匹配您网站的相应域。
为了完整起见,这是剩下的。
[0-9.]+
|
或者,我们可以有一系列数字和句点 - 一个IP地址。考虑到这个正则表达式有多复杂,我很惊讶他没有去(?:\d{1,3}\.){3}\d{1,3}
...
\[
[a-z0-9.]+
:
[a-z0-9.]+
:
[a-z0-9.:]+
\]
)
这是我们的最后一个选择;我认为这是针对IPv6的。无论如何,它是由冒号分隔的一系列十六进制数字。它要求它们在方括号内,我觉得很奇怪,特别是对于那些如此大量使用标签的论坛软件......
(?:
:
\d*
)?
在这里,我们得到冒号后面的一些数字选项。也就是说,这适用于包含端口的URL。
(?:
/
(?:
[a-z0-9\-._~!$&'($inline*+,;=:@|]+
|
%[\dA-F]{2}
)*
)*
好的,这里我们已经到了子目录,如开头的/
所示。否则,这是相同的“合法网址字符”匹配。
(?:
\?
(?:
[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+
|
%[\dA-F]{2}
)*
)?
(?:
\#
(?:
[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+
|
%[\dA-F]{2}
)*
)?
)
最后,由GET
表示的\?
传递的内容以及链接到中间页锚点的网址由\#
表示。
本节:
[a-z]$scheme*:/{2}
(?:
(?:
[a-z0-9\-._~!$&'($inline*+,;=:@|]+
|
%[\dA-F]{2}
)+
|
[0-9.]+
|
\[
[a-z0-9.]+
:
[a-z0-9.]+
:
[a-z0-9.:]+
\]
)
应该替换为这样的东西:
[a-z]$scheme*://
www\.example\.com
或者
[a-z]$scheme*://
(?:
www\.example\.com
|
192\.168\.0\.1
|
::ffff:192\.168\.0\.1
)
域名和IP地址与您的网站匹配。显然,你将不得不删除我所做的换行符和缩进。我会为你做的,但我认为这几乎是不值得的,因为你很难找到你把你的域放在所有那些中间的地方。
您可能希望为子域名或者遗漏www.
的人或者有你的人提供一些正则表达式。
您可能还想删除此内容:
(?:
:
\d*
)?
因为您可能不希望人们链接到您域中的其他端口。
第二个看起来具有大致相同的结构;正如评论所说,它只是让URL缺少协议指示符。