正则表达式:在前瞻之前捕获第一次出现

时间:2014-06-25 22:11:32

标签: regex

我正试图在特定单词之前捕获网址。唯一的麻烦是这个词也可能是域名的一部分。

示例:(我想在晚餐前捕捉所有东西)

https://breakfast.example.com/lunch/dinner/

https://breakfast.example.brunch.com:8080/lunch/dinner

http://dinnerdemo.example.com/dinner/

我可以使用:

^(.*://.*/)(?=dinner/?)

我遇到的麻烦是前瞻性似乎不够懒惰 所以以下是失败的:

https://breakfast.example.com/lunch/dinner/login.html?returnURL=https://breakfast.example.com/lunch/dinner/

抓住:

https://breakfast.example.com/lunch/dinner/login.html?returnURL=https://breakfast.example.com/lunch/

我都不明白为什么以及如何修复我的正则表达式。 也许我走错了路,但我怎么能抓住我的所有例子?

5 个答案:

答案 0 :(得分:4)

你可以使用一些懒惰:

^(.*?:\/\/).*?/(?=dinner/?)

Live demo

通过在正则表达式中间使用.*,您可以吃掉所有内容,直到找到匹配项的最后一个冒号。

顺便说一句,在正则表达式中间的

.*是非常糟糕的做法。它可能会导致长串中可怕的回溯性能下降。 .*?更好,因为它不情愿而不是贪婪。

答案 1 :(得分:4)

前瞻不一定是懒惰的,前瞻只是一个检查,在你的情况下是一个准固定的字符串。

你需要做什么懒惰显然是前瞻之前的子模式。

^https?:\/\/(?:[^\/]+\/)*?(?=dinner(?:\/|$))

注意:(?:/|$)就像一个边界,确保单词“dinner”后面跟一个斜杠或字符串的结尾。

答案 2 :(得分:1)

您的主要缺陷是使用贪婪匹配.*与非贪婪.*?

以下使用perl执行您想要的匹配,但正则表达式可以很容易地应用于任何语言。请注意在晚餐时使用字边界,这可能是你想要的,也可能不是你想要的:

use strict;
use warnings;

while (<DATA>) {
    if (m{^(.*?://.*?/.*?)(?=\bdinner\b)}) {
        print $1, "\n";
    }
}

__DATA__
https://breakfast.example.com/lunch/dinner/
https://breakfast.example.brunch.com:8080/lunch/dinner
http://dinnerdemo.example.com/dinner/

输出:

https://breakfast.example.com/lunch/
https://breakfast.example.brunch.com:8080/lunch/
http://dinnerdemo.example.com/

答案 3 :(得分:1)

另一种方式。

 # Multi-line optional
 # ^(?:(?!://).)*://[^?/\r\n]+/(?:(?!dinner)[^?/\r\n]+/)*(?=dinner)


 ^                    # BOL
 (?:
      (?! :// )
      . 
 )*
 ://
 [^?/\r\n]+           # Domain
 /     
 (?:
      (?! dinner )    # Dirs ?
      [^?/\r\n]+ 
      /          
 )*
 (?= dinner )

https://breakfast.example.com/lunch/晚餐/

https://breakfast.example.brunch.com:8080/lunch/晚餐

http://dinnerdemo.example.com/晚餐/

https://breakfast.example.com/lunch/晚餐/ login.html的?RETURNURL = https://breakfast.example.com/lunch/dinner/

答案 4 :(得分:0)

使用 python 3.7

import re
s = '''
https://breakfast.example.com/lunch/dinner/
https://breakfast.example.brunch.com:8080/lunch/dinner
http://dinnerdemo.example.com/dinner/
'''
pat = re.compile(r'.*(?=dinner)', re.M)
mo = re.findall(pat, s)
for line in mo:
    print(line, end=' ')

打印输出:

https://breakfast.example.com/lunch/
https://breakfast.example.brunch.com:8080/lunch/
http://dinnerdemo.example.com/