2014-06-25 72 views
4

我试图捕捉特定单词前的网址。唯一的麻烦是这个词也可能是该领域的一部分。正则表达式:先捕获第一个匹配项

例子:(我试图捕捉晚餐前的所有内容)

 
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/

我都不明白为什么以及如何修复我的正则表达式。 也许我在错误的轨道上,但我如何捕获我所有的例子?

+0

你用什么语言? –

回答

4

你可以使用一些懒惰:

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

Live demo

通过在您的正则表达式,你什么都吃,直到最后一个冒号,在那里找到了匹配的中间使用.*

.*在正则表达式中,顺便​​说一下,这是非常糟糕的做法。它会导致长字符串中可怕的回溯性能下降。 .*?更好,因为它不愿意而不是贪婪。

4

向前看并不一定是懒惰或不是,向前看只是一个支票,在你的情况下与准固定字符串。

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

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

注:(?:/|$)就是这样确保单词“晚餐”之后斜线或字符串的结束边界。

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/ 
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/