【问题标题】:preg_match_all: Why would "this" match but "that" won't?preg_match_all:为什么“this”匹配而“that”不匹配?
【发布时间】:2011-03-17 05:52:07
【问题描述】:

所以,我基本上是在尝试匹配对象标签内(包括)内的任何内容:

<?php preg_match_all('/<object(.*)<\/object>/', $blah, $blahBlah); ?>

它找到了一个匹配项:

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="400" height="250" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=9048799&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed type="application/x-shockwave-flash" width="400" height="250" src="http://vimeo.com/moogaloop.swf?clip_id=9048799&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" allowscriptaccess="always" allowfullscreen="true"></embed></object>

但它不会匹配这个:

<object width="400" height="300"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=5630744&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=5630744&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"></embed></object>

知道为什么吗?感谢您提供任何见解。


ETA:由于我的方法一开始可能有问题,这里有一些关于我正在尝试做的背景。

这是一个 Wordpress 网站。我正在使用一个将短标签转换为完整视频嵌入代码的插件。该插件最近(谢天谢地)更新以使代码更有效。

我正在尝试创建的功能只是在帖子中找到第一个视频对象,然后将其抓取以在网站的其他地方使用。

这是整个函数(其中一些只有在您使用过 Wordpress 时才有意义):

<?php
function catch_that_video() {
  global $post, $posts;
  $the_video = '';
  ob_start();
  ob_end_clean();
  $output = preg_match_all('/<object(.*)<\/object>/', $post->post_content, $vid_matches);
  $the_video = $vid_matches [1] [0];
  if(empty($the_video)){ $the_video = 0; }
  return $the_video;
}
?>

【问题讨论】:

  • 他们似乎都适合我。也许尝试在您的正则表达式中添加一个 s 标志。我发现 gskinner.com/RegExr 非常适合测试/调试。
  • 你为什么要使用正则表达式解析 HTML?
  • 使用 HTML 解析器。为什么?考虑字符串“......”。
  • Holly,可能是因为我不知道自己在做什么!施文,好点子。你能给我指出一个关于 HTML 解析的好参考吗?我对所有这些解析都很陌生,但我确实想把它做好。
  • 更新了代码,因为我意识到当我添加它时我进入了“自动美化”模式。它现在与输出完全相同(换行符和所有)。

标签: php regex preg-match-all


【解决方案1】:

唯一想到的是单行与多行。

/<object(.*)<\/object>/m

这应该匹配多行。

本手册页讨论了修饰符:

http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

更新:

经过进一步调查,m 不是正确的修饰符(来自手册):

m (PCRE_MULTILINE) 默认情况下,PCRE 将主题字符串视为由 单个“行”字符(即使 它实际上包含几个 换行符)。 “起点” 元字符 (^) 仅匹配 字符串的开始,而“结束 line" 元字符 ($) 仅匹配 在字符串的末尾,或之前 终止换行符(除非 D 修饰符 已设置)。这与 Perl 相同。 设置此修饰符时,“开始 行”和“行尾”结构 紧随其后匹配或 紧接在任何换行符之前 主题字符串,以及 就像开头和结尾一样。这是 相当于 Perl 的 /m 修饰符。如果 a中没有“\n”个字符 主题字符串,或没有出现 ^ 或模式中的 $,设置这个 修饰符无效。

(强调我自己的。)

正确的修饰符是 s,它允许点元字符 . 匹配换行符。

继续讨论更新后的问题,如果这些输入是简单字符串,则正则表达式本身会匹配这两个输入。我不知道是什么导致了实际问题。

$input = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="400" height="250" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=9048799&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed type="application/x-shockwave-flash" width="400" height="250" src="http://vimeo.com/moogaloop.swf?clip_id=9048799&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" allowscriptaccess="always" allowfullscreen="true"></embed></object>';

$input2 = '<object width="400" height="300"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=5630744&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=5630744&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"></embed></object>';

$matches = array();
preg_match_all('/<object(.*)<\/object>/', $input, $matches); 
echo '<br />$input<pre>';
var_dump($matches);
echo '</pre>';

$matches2 = array();
preg_match_all('/<object(.*)<\/object>/', $input2, $matches2); 
echo '<br />$input2<pre>';
var_dump($matches2);
echo '</pre>';

继续前进:

你想用这两行来完成什么?

ob_start();
ob_end_clean();

这会打开一个新的输出缓冲区并立即将其杀死。 (请参阅documentation 中有关堆叠输出缓冲区的内容。)

是否有理由将其设置为 0,而不是说 null

if(empty($the_video)){ $the_video = 0; }

就个人而言,我会在声明它时将其设置为null,并且如果没有匹配项,则依赖于不破坏它。这就是我编写该函数的方式,假设 $post 是一个 WordPress 全局变量。 (就我个人而言,我只是将它传递给函数,因为我鄙视大多数全局变量。)

function catch_that_video() 
{
  global $post;

  $the_video = null;
  $vid_matches = array();

  if(preg_match('/<object.*<\/object>/', $post->post_content, $vid_matches))
  {
    $the_video = $vid_matches[0];
  }

  return $the_video;
}

我将其更改为使用preg_match 而不是preg_match_all,因为您只使用了第一个匹配项。当然,如有必要,可以将其修改为使用preg_match_all。但是,创建适当的正则表达式会很痛苦。 (将s 修饰符添加到上述正则表达式以处理多行将获取从第一个打开&lt;object&gt; 标记到最后一个关闭&lt;/object&gt; 标记的所有内容。我什至不想考虑尝试来使用正则表达式来覆盖多行并获取单个 &lt;object&gt;...&lt;/object&gt; 块。)

但是,这并不能回答关于为什么第二个对象块不匹配的原始问题。我会将我的调查重点放在试图发现两个字符串之间的区别上。如果问题是行尾之间的区别,我会在 Linux 上使用 VIM 之类的东西,因为它会显示 `^M' 代替行尾中的 \r。字符串的html编码怎么样?这可能是一个问题吗?

【讨论】:

  • 但是这些输入中的 both 不都使用多行吗?
  • @Rob Kennedy 假设输入的格式与此问题中的格式相同。 (这不是一个糟糕的假设。)当我想不出正则表达式对两者都不起作用的原因时,我决定放弃这个假设。
  • 谢谢,那个修饰符不起作用,但我正在检查是否有其他任何可能适用。不过,我开始发现我的方法从一开始就是错误的。
  • @Kerri 这基本上是我们不应该使用正则表达式解析 HTML 的原因。正则表达式很强大,但 HTML 的使用变化太大。也就是说,我仍然很好奇这里的问题是什么。
  • 更新了代码,因为我意识到当我添加它时我进入了“自动美化”模式。它现在与输出完全相同(换行符和所有)。
猜你喜欢
  • 2014-12-23
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 2016-04-03
  • 1970-01-01
  • 2017-04-25
相关资源
最近更新 更多