具有可选前缀的正则表达式中的负向lookbehind

时间:2014-10-11 17:58:36

标签: regex scala regex-lookarounds

我们使用以下正则表达式来识别网址(this gist来自Jim Gruber)。这是使用scala.util.matching在Scala中执行的,后者又使用java.util.regex

(?i)\b((?:https?:(?:/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?!js)[a-z]{2,6}/)(?:[^\s()<>{}\[\]]+)(?:[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?!js)[a-z]{2,6}\b/?(?!@)))

此版本已转发正斜杠,Rubular

(?i)\b(((?:https?:(?:\/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?!js)[a-z]{2,6}\/)(?:[^\s()<>{}\[\]]+)(?:[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?!js)[a-z]{2,6}\b\/?(?!@))))

以前前端只向后端发送明文,但是现在他们允许用户为网址创建锚标签。因此,后端现在需要识别已经在锚标签中的URL 除了。我最初试图以负面的loohbehind来完成这个,忽略了带有href="前缀的网址

(?i)\b((?<!href=")((?:https?: ... etc

问题是我们的url正则表达式非常自由,认识到http://www.google.comwww.google.comgoogle.com - 给出了

 <a href="http://www.google.com">Google</a>

否定后备将忽略http://www.google.com,但正则表达式仍会识别www.google.com。我想知道是否有一种简洁的方式告诉正则表达式“忽略www.google.comgoogle.com,如果它们是被忽略的http(s)://www.google.com”的子字符串

目前我在url正则表达式匹配上使用过滤器(代码在Scala中) - 这也忽略了带有<a href="http://www.google.com">www.google.com</a>前缀和{的URL的链接文本(>)中的URL {1}}后缀。如果在正则表达式中执行此操作会使已经复杂的正则表达式更加难以理解,我宁愿坚持使用过滤器。

</a>

3 个答案:

答案 0 :(得分:1)

您似乎不仅要忽略www.google.comgoogle.com,如果它们是忽略的http(s)://www.google.com"的子字符串,而是来自先前忽略的部分的任何子字符串片段...在这种情况下,您可以使用一些代码来解决这个问题!请参阅正则表达式:

(a href=")?(?i)\b(((?:https?:(?:\/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?!js)[a-z]{2,6}\/)(?:[^\s()<>{}\[\]]+)(?:[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?!js)[a-z]{2,6}\b\/?(?!@))))
^^^^^^^^^^^

我不擅长斯卡拉,但你可能会这样做:

val links = new Regex("""(a href=")?(?i)\b(((?:https?:... """.r, "unwanted")
val unwanted = for (o <- links findAllMatchIn text) yield o group "unwanted"

如果unwantedscala.Null,则匹配很有用。

您可以通过替换替代方案来解决需要替换的问题:

a href="(?i)\b(?:(?:https?:(?:\/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?!js)[a-z]{2,6}\/)(?:[^\s()<>{}\[\]]+)(?:[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?!js)[a-z]{2,6}\b\/?(?!@)))|((?i)\b(((?:https?:(?:\/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?!js)[a-z]{2,6}\/)(?:[^\s()<>{}\[\]]+)(?:[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?!js)[a-z]{2,6}\b\/?(?!@)))))

管道|后面的正则表达式的第二部分被分组为捕获组。您可以使用第一个组替换此正则表达式:\1

类似的问题:

答案 1 :(得分:1)

<a href=\S+|\b((?:https?:(?:\/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?!js)[a-z]{2,6}\/)(?:[^\s()<>{}\[\]]+)(?:[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?!js)[a-z]{2,6}\b\/?(?!@)))

<a href=(?:(?!<\/a>).)*<\/a>|\b((?:https?:(?:\/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?!js)[a-z]{2,6}\/)(?:[^\s()<>{}\[\]]+)(?:[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?!js)[a-z]{2,6}\b\/?(?!@)))

试试这个。它本质上的作用是:

  1. 消费所有href个链接,以便以后无法匹配

  2. 不会捕获它,因此它不会出现在groups中。

  3. 像以前一样处理其余的事情。

  4. 参见演示。

    http://regex101.com/r/vR4fY4/17

答案 2 :(得分:0)

如果只将<a href=部分添加为可选组,那么在检查匹配时,只返回该组为空的匹配项?