简单分析 b 站站内链接的正则匹配以及吐槽

2020-08-05 18:55:09 +08:00
 LXGShadow

在 V2EX 里发我就尽量简洁一些。

原文地址: https://www.lxgshadow.us/blog/article-detail/46

在学正则,想找点例子来看看,看了看 b 站的一部分正则匹配,我真的人傻了。

刚刚开始学习正则,有错误请指出。


Part1-专栏投稿中站内链接的正则匹配

总之都知道 b 站专栏里有添加站内链接的操作,然后检测是否是站内链接是直接写 js 里的。

翻出来就是这样

1.^( http:)?( https:)?(\/\/)?((([a-zA-Z0-9_-])+(\.)?){1,2}\.)?(bilibili.com)+(:\d+)?(\/((\.)?(\?)?=?&?%?[#!a-zA-Z0-9_-](\?)?)*)*$

2.^( http:)?( https:)?(\/\/)?(([a-zA-Z0-9_-])+(\.)?){0,2}(\.biligame.com)+(:\d+)?(\/((\.)?(\?)?=?&?%?[#!a-zA-Z0-9_-](\?)?)*)*$/i

3.^( http:)?( https:)?(\/\/)?(acg.tv)+(:\d+)?(\/((\.)?(\?)?=?&?%?[#!a-zA-Z0-9_-](\?)?)*)*$

4.^(bilibili:\/\/)(\S)+$

先吐槽一下匹配协议的正则^( http:)?( https:)?(\/\/)?,我寻思着他的目的应该是匹配 http://,https://,// 的其中之一。但是用?我是没想到的,这样子连 "http:https://" 都能匹配到。

写个类似这样的: (( http(s)?:\/\/)|(\/\/))? 就可以解决问题了

再来说说匹配主域名的(bilibili.com)+,(.biligame.com)+。匹配域名匹配一遍就够了啊,用+干啥,难道你站域名还存在 bilibili.combilibili.com ? (虽然在 1,2 里前面有做最多匹配 3 级域名,这个+似乎也不会起到啥作用)

(([a-zA-Z0-9_-])+(\.)?){0,2} 这段大概是匹配 1-3 级域名,我觉得还行.....个头。

([a-zA-Z0-9_-])+ 没多大问题, 但是 (\.) 加 ? 干嘛,匹配子域名.是必须的啊。哦,原来是为了后面 \.biligame.com

但是这问题也很大啊,既然都给了?了,那我也可以加 . 啊。如果按这个正则的话 a.a..biligame.com 不是照样能匹配到。

\.biligame.com 带来的另一个问题就是这段子表达式根本匹配不到 biligame.com, 必须前面加个 . 才行 (.biligame.com)

第一条 bilibili.com 的也是大同小异, 我就不分析了。

同样给一个可能可以作为替代的 ([a-zA-Z0-9_-]+\.){0,2}(biligame.com)


Part2-评论区中站内链接的正则匹配

这段由@Rorical 的文章《优雅的在哔哩哔哩评论区发送链接》 所启发

判断是否为官方链接的代码依旧写死在 commet.js 里。

( http(s)?:\/\/)?([a-z0-9A-Z]+.)?(bilibili.(com|tv|cn)|biligame.(com|cn)|(bilibiliyoo|im9).com|biliapi.net|b23.tv|sugs.suning.com|kaola.com)(\$|\/|)([\/.$*?~=#!%@&-A-Za-z0-9_]*)(?![^<>]*>|[^"]*?<\/a)

先说个非常离谱的 (\$|\/|) 我先大胆分析了一下,这段子表达式的功能有两个,第一个: 如果该 url 没有后面的 path,那么用 $ 直接就结束了。如果有后面的 path,那么必须先匹配到一个 / 才行。

但是我看到这段的时候人都傻了,\$ 好好的 $ 你给他转义干啥啊。 哪个正常人写 url 里带$的。

还有 (\$|\/|) 子表达式里为什么有三个 | 。匹配空气嘛? 结合后面的正则,难道是想匹配 bilibili.comoihfgiu2b34rkeajsiflbnaiokgba?

然后就是最最最最最最最最最最离谱的了,所有的 . 都没有转义。

先是匹配子域名子表达式里的 . 没有转义 ([a-z0-9A-Z]+.)?。那么该表达式几乎等同于 ([a-z0-9A-Z]{1,})? 了?匹配无中生有的子域名?

然后是域名里的 . 也都没转义。

结合以上的漏洞,构建一个能够被匹配的二级域名都是轻轻松松的。

当然,评论区这段我不希望 b 站修复。留着还挺有用的。

当然,评论区这段我不希望 b 站修复。留着还挺有用的。

当然,评论区这段我不希望 b 站修复。留着还挺有用的。


后端正则匹配猜测

前景提要: https://www.v2ex.com/t/684939

在测试中发现

尝试 https://www.bilibili.com -> 成功

尝试 https://www.biligame.com -> 成功

尝试 https://www.im9.com -> 成功

尝试 https://www.biliapi.net -> 成功

尝试 https://www.bilibili.co -> 成功

尝试 https://aabilibili0com -> 成功, 说明没有转义.

可以首先构建出一段子表达式(bilibili.com|biligame.com|im9.com|biliapi.net|bilibili.co)

尝试 https://www.bilibili.com -> 成功

尝试 https://a.a.a.a.a.bilibili.com -> 成功

尝试 www.bilibili.com -> 失败

尝试 https://bilibili.com -> 失败

尝试 http:https://www.bilibili.com -> 失败

由此可以推断出,后端的正则匹配必须有 http 或者 https 以及一个二级域名

结合上一段,构建出子表达式

^( http(s)?:\/\/)([a-z0-9A-Z]+.)+(bilibili.com|biligame.com|im9.com|biliapi.net|bilibili.co)

接下来尝试 2 级域名

尝试 https://aabilibili0com.a.a -> 失败

尝试 https://aabilibili0com/.a.a -> 成功

尝试 https://aabilibili0com -> 成功

尝试 https://aabilibili0com/ -> 成功

由此构建子表达式

($|\/)([\/.$*?~=#!%@&-A-Za-z0-9_]*)(?![^<>]*>|[^"]*?<\/a)

结合起来 推测后端正则表达式为

^( http(s)?:\/\/)([a-z0-9A-Z]+.)+(bilibili.com|biligame.com|im9.com|biliapi.net|bilibili.co)($|\/)([\/.$*?~=#!%@&-A-Za-z0-9_]*)(?![^<>]*>|[^"]*?<\/a)

结果 . 依旧没有转义。

虽然不排除后端根本用的不是正则。

当然,这段我依旧不希望 b 站修复。留着还挺有用的。

当然,这段我依旧不希望 b 站修复。留着还挺有用的。

当然,这段我依旧不希望 b 站修复。留着还挺有用的。


综上所述,我有理由怀疑,写这些正则的人可能是闭着眼睛写的。

虽然这些基本无伤大雅,也不会对用户体验造成任何影响 (删掉)甚至增加了我的使用体验(删掉),有些在后端会也会被过滤掉。

但是麻烦走点心好嘛?

2530 次点击
所在节点    分享发现
2 条回复
lxk11153
2020-08-05 19:06:13 +08:00
强👍。不去上海工作可惜了
huermos
2020-08-06 18:41:36 +08:00
说不定就是闭着眼写的,反正功能实现了就可以,也没有严重 bug
程序员工作很多,很累哒

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/695930

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX