DOM / XPath(即正确)方式:
<?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
是被解释为八进制字符定义(如此处定义),因此您的表达式中有一个文字0x01
(标题开头)字符,而不是\1
您希望 PCRE 用作的字符串反向参考。
我发现当我遇到这样的问题时,一个好的起点是简单echo
地筛选表达式以查看 PHP 如何插入您在脚本中声明的字符串。这里是该特定问题的演示。
([\"']??)
- 第二个问号是打破它。我实际上不确定你想用这个来完成什么,它只是一个错误的类型吗?我很难弄清楚 PCRE 是如何解释这一点的,以及它究竟为什么会破坏它,但我只想说它确实如此,并且第二个问号需要去掉。FTR,它的作用是表达式仍然匹配<img>
标签,但是下面的捕获组(你真正想要的数据)是空的。
现在让我们分解正则表达式,看看如何改进它:
<\s*?img
- 这里的非贪婪*
是没有意义的,因为\s
只匹配空白,下一个序列将是 alpha,<\s*img
就足够了。我实际上不确定 HTML 标记是否允许在开头<
和标记名称之间有前导空格,但我想允许它不会有任何害处,因为适当的解析器可能会这样做。
\s[^>]*?src=(["']??)
- 如前所述??
,捕获组中的 正在破坏表达式,我不确定您首先要尝试使用它做什么。另外,我再次认为非贪婪*
是没有意义的,因为标签将以 结尾>
,如果我们最后还没有找到src
它,那么它无论如何都不是匹配的。另外,如果我们在不应该出现但解析器可能允许的地方允许空格,我们可能应该在=
. 我会将其重写为\s[^>]*src\s*=\s*(["']?)
.
([^"' >]*?)\1
- 假设您担心能够处理未引用的属性,这里没有抱怨。当然,如果您确实知道属性将始终被引用,您可以简单地使用并从前面我们确定使用的引用类型的捕获组中([^\1]*?)\1
删除。?
[^>]*?>
- 这里没有抱怨。
/si
-修饰符没有意义,因为表达式中的任何地方s
都没有s。.
它没有任何害处,但也没有帮助,所以它是多余的。
因此,将所有这些放在一起,这就是我编写正则表达式的方式:
/<\s*img\s[^>]*src\s*=\s*(["']?)([^"' >]*?)\1[^>]*>/i
...当转换为带有正确转义引号的 PHP 字符串声明时,如下所示:
$expr = '/<\s*img\s[^>]*src\s*=\s*(["\']?)([^"\' >]*?)\1[^>]*>/i';
...顺便说一句,效果很好。
现在,即使考虑到额外的代码,我仍然认为 DOM 方法更好,因为它可能会捕获我的 regex Skillz 忘记的边缘情况。虽然诚然 regex 似乎确实有点快。