我有这个正则表达式:
preg_match_all("/<\s*?img\s[^>]*?src=([\"']??)([^\"' >]*?)\1[^>]*?>/si", $content, $m);
我们的想法是在一段HTML中找到所有图像链接。鉴于此内容:
<p>
<img alt="" src="/emailimg/interdigital_old.jpg" style="width: 377px; height: 245px; " />Some text here.</p><a href="site.html">test</a>
执行正则表达式后,$ m是一个包含3个空数组的数组,但如果我用this site测试它,结果是:
Array
(
[0] => Array
(
[0] => <img alt="" src="/emailimg/interdigital_old.jpg" style="width: 377px; height: 245px; " />
)
[1] => Array
(
[0] => "
)
[2] => Array
(
[0] => /emailimg/interdigital_old.jpg
)
)
有什么问题?这是配置问题吗?
答案 0 :(得分:4)
<?php
$html = '
<p>
<img alt="" src="/emailimg/interdigital_old.jpg" style="width: 377px; height: 245px; " />Some text here.</p><a href="site.html">test</a>
';
$dom = new DOMDocument('1.0');
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$links = array();
foreach ($xpath->query('//img/@src') as $img) $links[] = $img->value;
print_r($links);
修改强>
你的正则表达式不起作用的原因有两个:
您已使用双引号字符串声明了正则表达式。这通常会导致您不期望并且不完全明显的事情,因为双引号字符串将在传递给PCRE之前插入某些转义序列。在您的情况下导致的问题是\1
被解释为八进制字符定义(定义为here),因此您的表达式具有文字0x01
(标题的开头)字符在其中,而不是您希望PCRE用作后向参考的\1
字符串。
我发现当我遇到这样的问题时,一个好的起点就是简单echo
屏幕上的表达式,以查看PHP如何插入您在脚本中声明的字符串。 Here是对该特定问题的证明。
([\"']??)
- 第二个问号是打破它。我真的不确定你要用这个来完成什么,这只是一个错误的类型吗?我很难确定PCRE究竟是如何解释这一点的,以及为什么它会破坏它,但足以说它确实如此,第二个问号需要去。 FTR,它具有的效果是表达式仍然匹配<img>
标签,但是下面的捕获组(您实际想要的数据)是空的。
现在让我们分解正则表达式,看看如何改进它:
<\s*?img
- 这里的非贪婪*
毫无意义,因为\s
只匹配空格,下一个序列将是alphas,只需<\s*img
即可。我实际上并不确定HTML标记是否允许在开头<
和标记名称之间有前导空格,但我认为它不会造成任何伤害,因为正确的解析器可能会。\s[^>]*?src=(["']??)
- 如前所述,捕获组中的??
打破了表达式,我不确定您首先尝试使用它做什么。另外,我认为非贪婪的*
毫无意义,因为标记将以>
结尾,如果我们还没有找到src
,那么反正不是一场比赛。另外,如果我们允许在不应该是解析器可能允许的地方使用空格,我们应该允许它在=
附近。我将其重写为\s[^>]*src\s*=\s*(["']?)
。([^"' >]*?)\1
- 假设您担心能够处理不带引号的属性,请不要在此处投诉。当然,如果你做知道将始终引用属性,你可以简单地使用([^\1]*?)\1
并从前面的捕获组中删除?
,我们确定使用的报价类型[^>]*?>
- 此处没有投诉。/si
- s
修饰符毫无意义,因为表达式中的任何位置都没有.
。它没有任何伤害,但它也没有帮助,所以它是多余的。所以,把所有这些放在一起,在这里我将如何编写正则表达式:
/<\s*img\s[^>]*src\s*=\s*(["']?)([^"' >]*?)\1[^>]*>/i
...当转换为带有正确转义引号的PHP字符串声明时,如下所示:
$expr = '/<\s*img\s[^>]*src\s*=\s*(["\']?)([^"\' >]*?)\1[^>]*>/i';
......顺便说一下works nicely。
现在,我仍然认为即使考虑额外的代码,DOM方法也更好,因为它可能会捕获我的正则表达式技巧已经忘记的边缘情况。虽然可以肯定正则表达式确实是somewhat faster。