在 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 站修复。留着还挺有用的。
综上所述,我有理由怀疑,写这些正则的人可能是闭着眼睛写的。
虽然这些基本无伤大雅,也不会对用户体验造成任何影响 (删掉)甚至增加了我的使用体验(删掉),有些在后端会也会被过滤掉。
但是麻烦走点心好嘛?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.