【问题标题】:Are these regex patterns different?这些正则表达式模式不同吗?
【发布时间】:2012-06-23 18:45:48
【问题描述】:

我一直在开发的网站不会使用 PHP (preg_match) 正则表达式模式匹配数据,这种模式似乎在我测试过的其他任何地方都可以使用。该模式是:

<channel.*?>(.*?)</channel>

它与具有频道标签的 RSS 提要相匹配。

现在我正在处理的服务器只有在将其更改为时才会产生正确的结果:

<channel.*?>(.*)?</channel>

我的正则表达式不是世界上最好的,所以我想知道是否有人可以告诉我这两种模式之间是否有任何显着差异。

小记:我意识到使用 SimpleXML 等可能会更好,但是这个正则表达式来自以前的应用程序,由于各种原因我不允许更改它。

提前感谢您提供任何见解。

【问题讨论】:

  • ' 是您的 PCRE 分隔符吗?如果是这样,s 修饰符可能会也可能不会有所作为(我不完全确定)。
  • 是的 ' 是 PCRE 分隔符。它是由最初编写代码的人使用的,通常使用#~

标签: php regex preg-match


【解决方案1】:

语句(.*) 表示“选择是零个或多个字符”,而结尾的? 使其成为可选匹配项。相比之下,(.*?) 使用的是“懒惰之星”(*?),它首先尝试完全跳过匹配。更多信息请查看this

要了解普通(贪婪)星和惰性星之间的区别,请查看以下 PHP 示例,并注意贪婪星与给出的模式进行最大匹配,而惰性星“满足匹配模式后立即放弃:

$inputs = array( 'axb' , 'axxxb' , 'axbxb' , 'axbxxxb' );

// GREEDY STAR (NORMAL)
foreach( $inputs as $input )
{
  preg_match( '/a.*b/' , $input , $greedy );
  $greedy_matches[] = $greedy[0];
}

print "<pre>";
print_r( $greedy_matches );
print "</pre>";
/* 
Array
(
    [0] => axb
    [1] => axxxb
    [2] => axbxb
    [3] => axbxxxb
)
*/



// LAZY STAR
foreach( $inputs as $input )
{
  preg_match( '/a.*?b/' , $input , $lazy );
  $lazy_matches[] = $lazy[0];
}

print "<pre>";
print_r( $lazy_matches );
print "</pre>";
/* 
Array
(
    [0] => axb
    [1] => axxxb
    [2] => axb
    [3] => axb
)
*/

【讨论】:

  • 谢谢。这帮助很大(感谢所有回答的人)。我有一个小问题,原来(.*?) 的代码似乎在任何地方都可以正常工作,包括我自己的服务器,但是这台服务器似乎只能与(.*)? 保持一致。这是因为“懒惰的明星”还是该服务器有什么奇怪的地方&它的正则表达式匹配?
  • Lazy star 来自 Perl、IIRC,因此可能是此特定服务器使用的正则表达式库没有实现 lazy star。
  • 刚刚检查过,它确实有与我的版本不同的 perl 版本,所以这一定是我听过的最好的解释。谢谢。
  • 为了确定,您可以尝试将模式 /a.*?b/ 与输入 axbaxbxb 进行匹配。一个普通的(贪婪的)星将匹配两个示例中的整个字符串,但一个惰性星将只匹配两个示例中的axb。我用一个例子扩展了我的答案。
  • 感谢您扩展您的答案。这绝对可以解释事情。我不再可以访问服务器,但这是我第三次遇到它,所以下次发生时一定会检查它。
【解决方案2】:

我的猜测是,您实际上并不希望操作员本身变得懒惰。惰性运算符通常会尝试尽可能少地匹配,这在处理大量可能不规则的数据时很可能会产生意想不到的结果。通过将问号放在贪婪组的末尾,您可以向贪婪组添加可选匹配,而不是使组非贪婪(惰性)。如果您想详细了解贪婪和懒惰之间的区别,请查看:http://www.regular-expressions.info/possessive.html

【讨论】:

    【解决方案3】:

    请提供您尝试匹配的文本示例。

    '<channel.*' will match anything starting with <channel
    
    '?>' will match a single character followed by > (so '1>', '2>', 'b>' etc)
    

    如果你想匹配 只需使用模式

    '#<channel>(.*)</channel>#'
    

    【讨论】:

      【解决方案4】:

      在正则表达式中,* 表示 0 次或多次 - 不需要添加 ?在它之后。

      编辑:正如我现在从 cmets 了解到的那样,贪婪会有所作为。一个小测试用例:

      var_dump(preg_replace('/<channel.*?>(.*?).*<\/channel>/', '$1', '<channel>asd</channel>'));
      var_dump(preg_replace('/<channel.*?>(.*)?.*<\/channel>/', '$1', '<channel>asd</channel>'));
      

      输出

      string(0) ""
      string(3) "asd"
      

      如您所见,我使用的是(.*?).*(.*)?.*,所以贪婪会有所作为。但是,由于它不一样,在给定的示例中,我看不出它是如何产生影响的。

      【讨论】:

      • *? 是一个不贪心的零个或多个量词。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 2012-08-28
      • 2021-08-11
      相关资源
      最近更新 更多