2015-04-06 12 views
0

如果我有一个包含文本:的preg_match:通过匹配一个字返回完整的URL里面

<h1> Test </h1> 
<some html elements> 
<a href="www.example.com/test?abc=xxxx&def=yyyy&ghi=zzzzz"></a> 
<more html elements> 

如何通过匹配有 “ABC = XXXX”,所以我得到一个字的preg_match:

www.example.com/test?abc=xxxx&def=yyyy&ghi=zzzzz 
+1

你甚至尝试过什么吗? – Rizier123

+0

是的。第一个是提取“xxx”,所以我的正则表达式是'/abc=(.*?)\&/'。但现在我需要获取整个网址。 – typescript

+1

^在您的问题中添加您的尝试 – Rizier123

回答

0

当你在这里搜索URL时,有必要弄清楚是什么使它与上下文有所不同。

一般不包含空格,往往它封闭在某种报价或括号,使得它很容易的识别网址:

URL -- surrounded by whitespace -- 
"URL" -- quoted like in your example -- 
<URL> -- the class way of marking an URL -- 

这将使描述网址为下面的表达式

~(?P<url>[^\s<>"\']+)~ 

运行仅此就在您的示例文件已经做了某种这里工作的,它提供了13笔,其中12个是假阳性,但网址是:

#1 h1,   #2 Test,   #3 /h1, 
#4 some,   #5 html,   #6 elements, 
#7 a,    #8 href=,   

#9 www.example.com/test?abc=xxxx&def=yyyy&ghi=zzzzz, 

#10 /a,   #11 more,   #12 html, 
#13 elements. 

幸运的是,你有更多的标准什么URL在你的情况下,所以这可以被添加。例如查询字符串必须在那里。它,它必须包含一个问号:

~(?P<url>[^\s<>"\'?]+\?[^\s<>"\'?]+)~ 

问号已被排除在允许的字符组,该组有两个被分割和问号,现在在中间需要。由于URL只能包含一次,所以这非常好。

现在只剩下一场比赛了。

www.example.com/test?abc=xxxx&def=yyyy&ghi=zzzzz 

这是因为现在实在是太难看了,让我们写这更好的了下来:

~ 
    (?(DEFINE) 
     (?<Chars> [^\s<>"\'?]+) 
    ) 

    (?P<url> (?&Chars) \? (?&Chars)) 
~x 

而这还不是又不失结束,因为你清楚地知道你在找什么,那abc=(.*?)&部分。这有点不对,价值被&终止,所以它不能包含它。与问号,这应该被放入它的模式,因为这样的值可以在URL的结尾为好,下面剩下的就作出可选:

~ 
    (?(DEFINE) 
     (?<Chars> [^\s<>"\'?]+) 
     (?<Val> [^\s<>"\'?&]*) 
    ) 

    (?P<url> (?&Chars) \? (?&Chars)? abc = (?P<value> (?&Val)) &? (?&Chars)? ) 
~x 

所以只要你”对一个特定的URL感兴趣,使用正则表达式做这件事相对简单,但是:文档中的URL不能被标准化,并且其他类似的问题可能会发生。因此,通常最值得先对URL进行规范化处理,然后继续处理。例如,在查询信息部分查看URL参数时。

在写这篇文章的时候我实际上认为,从文档中获取URL的过滤应该独立于解析方法。正如其他用户所评论的,您可能想使用HTML解析器而不是正则表达式。或者你也许想要两个。

我们先来关注正则表达式场景。这是一个正确的URL解析正则表达式。作为预防措施,网址的最大长度已经从6到256个字节的限制:

$matcher = new PregStringMatcher('~([^\s<>"\']{6,256})~'); 
$segments = new StringMatcherIterator($matcher, $input); 
$all  = new DecoratingIterator($segments, 'Net_URL2'); 
$urls  = new CallbackFilterIterator($all, function (Net_URL2 $url) { 
    return isset($url->getQueryVariables()['abc']); 
}); 

foreach ($urls as $url) { 
    echo $url->getQueryVariables()['abc'], ' - ', $url, "\n"; 
} 

此代码使用的类从IteratorGarden和梨Net_URL2。输出是(我修改你的HTML示例一点点):

xxxx - www.example.com/test?%61%62%63=xxxx&def=yyyy&ghi=zzzzz 

如果你现在考虑切换到HTML解析器,你不需要改变太多,代码。由于过滤逻辑是一样的,所有你需要的是Exchange中的基础Traversable的

$doc = new DOMDocument(); 
$saved = libxml_use_internal_errors(true); 
$doc->loadHTML($input); 
libxml_use_internal_errors($saved); 

$attributes = (new DOMXPath($doc))->query('//@href'); 
$segments = new DecoratingIterator($attributes, function (DOMAttr $attr) { 
    return $attr->nodeValue; 
}); 

的其余代码可以保持不变,结果在这种情况下是一样的。所以我希望这些检查是有用的,并展示如何处理正则表达式以及如何添加更多检查的一些方法。

这里的代码示例与正则表达式和HTML解析器完全兼容。 URL过滤器在两者中都是相同的:

<?php 
/** 
* preg_match: return entire url by matching a word inside it 
* 
* @link http://stackoverflow.com/a/29481904/367456 
*/ 

require __DIR__ . '/vendor/autoload.php'; 

$input = <<<BUFFER 
<h1> Test </h1> 
<some html elements> 
<a href="www.example.com/test?%61%62%63=xxxx&def=yyyy&ghi=zzzzz"></a> 

<more html elements> 
BUFFER; 

// Regex based retrieval 

$matcher = new PregStringMatcher('~([^\s<>"\']{6,256})~'); 
$segments = new StringMatcherIterator($matcher, $input); 
$all = new DecoratingIterator($segments, 'Net_URL2'); 
$urls = new CallbackFilterIterator($all, function (Net_URL2 $url) { 
    return isset($url->getQueryVariables()['abc']); 
}); 

foreach ($urls as $url) { 
    echo $url->getQueryVariables()['abc'], ' - ', $url, "\n"; 
} 

// DOMDocument based retrieval 

$doc = new DOMDocument(); 
$saved = libxml_use_internal_errors(true); 
$doc->loadHTML($input); 
libxml_use_internal_errors($saved); 

$attributes = (new DOMXPath($doc))->query('//@href'); 
$segments = new DecoratingIterator($attributes, function (DOMAttr $attr) { 
    return $attr->nodeValue; 
}); 
$all = new DecoratingIterator($segments, 'Net_URL2'); 
$urls = new CallbackFilterIterator($all, function (Net_URL2 $url) { 
    return isset($url->getQueryVariables()['abc']); 
}); 

foreach ($urls as $url) { 
    echo $url->getQueryVariables()['abc'], ' - ', $url, "\n"; 
} 
相关问题