Javascript正则表达式:查找所有<a>标签外的URL - 嵌套标签

3

我已经编写了这个正则表达式代码:

((https?|ftps?):\/\/[^"<\s]+)(?![^<>]*?>|[^<>]*?<\/)

第一组捕获HTML中的所有链接,第二组是负向预查以排除任何作为属性和内容的标签内部的任何部分。
我希望只有标签被排除 - 所以解决方案可能是仅修改最后一个术语为:
[^<>]*?<\/a>

但是如果我有嵌套标签(例如<b></b><a>内),那么现在就会出现问题。

这是我正在处理的示例:https://regex101.com/r/lM3hC5/6 (应该有10个匹配项)。

否定先行断言对我来说仍然很棘手。我认为以下内容应该有效,但它却无效:

(?!<a.+?<\/a>)

https://regex101.com/r/hT1cG5/1

这些是最近帮助我的讨论:


这个问题难道不够严重吗?我们应该停止依赖正则表达式从HTML中提取文本,而是使用DOM解析器。 - Wiktor Stribiżew
@WiktorStribiżew 你所说的DOM解析器是指什么?类似这样的吗?http://simplehtmldom.sourceforge.net/manual.htm - Shafizadeh
我只是在想,如果我的代码使用正则表达式非常简洁明了,那么这是否可能呢? - Klaidonis
@user2943191 我在某个地方读到,使用正则表达式应该是最后的选择.. - Shafizadeh
这里是一个可能的基于DOM的解决方案 - Wiktor Stribiżew
1个回答

6
事实证明,可能最好的解决方案如下:
((https?|ftps?):\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

看起来负向先行断言只能在量词开始而不是字符串时正常工作。对于这种情况,实际上我们只能进行回溯。
同样,我们只想确保HTML标签中的内容不会出错。然后我们从</a开始回溯,直到第一个"符号(因为它不是有效的URL符号,但<>符号存在嵌套标记)。
现在也可以正确找到<a>标签内部的嵌套标记。当然,代码并不完美,但它应该可以处理几乎任何简单的HTML标记。只是你可能需要稍微小心一些:
  • 将引号放置在<a>标签内;
  • 不要在没有任何属性的<a>标签上使用此算法(placeholders);
  • 除非<a>标签内的URL在任何双引号之后,否则您可能需要避免使用多个嵌套标签/行。


这是一个非常好而混乱的例子(最后一项匹配不应被找到,但它确实被找到了):

https://regex101.com/r/pC0jR7/2

很遗憾,这个前瞻不起作用:(?!<a.*?<\/a>)

也许有人能找到更好的方法来优化这段代码。 - Klaidonis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接