2012-08-30 91 views
0

我有一个正则表达式:用正则表达式奇怪的问题

~(?P<opening>{(?P<inverse>[!])?block:(?P<name>[a-z0-9\s_-]+)(:(?P<function>[a-z0-9\s_-]+)([\s]?\((?P<params>[^)]*)\))?)?})(?P<contents>[^{]*(?:\{(?!/?block:[a-z0-9\s_-]+\})[^{]*)*)(?P<closing>{/block:(?P=name)})~is 

它试图匹配以下:

<ul>{block:menu} 
    <li><a href="{var:link}">{var:title}</a> 
{/block:menu}</ul> 

工作正常,但是当块标签的第三部分是引入例如:{block:menu:thirdbit}它无法匹配它,但是如果你砍掉正则表达式的结尾将其修剪到下面它确实匹配意味着该模式是好的,但其他事情已经出错:

(?P<opening>{(?P<inverse>[!])?block:(?P<name>[a-z0-9\s_-]+)(:(?P<function>[a-z0-9\s_-]+)([\s]?\((?P<params>[^)]*)\))?)?})

任何想法发生了什么问题?

+3

便宜枪:是的。你正试图用正则表达式解析HTML。不是正确的策略。不,但老实说:这个正则表达式应该做什么?阅读现在的方式几乎是不可能的。 –

+0

[Rubular](http://rubular.com/r/MXuqL0XbWa)适合我。 (剥离指定的捕获,并用数字版本“\ 3”替换名为backreference。) –

+0

如前所述,此正则表达式仅为_unreadable_。它的正则表达式就像这个一般负责给正则表达式一个坏的说唱。那是;非常复杂,有许多层级的嵌套分组以非自由空间模式写在一行上,绝对没有评论。难道不会有人想到孩子! – ridgerunner

回答

1

只是一个想法:将所有{block:menu}和类似的元素转换到他们自己的命名空间中的XML元素。然后你可以使用xpath并完成工作。你甚至应该能够在飞行中做到这一点。

1

首先,Tim正确地指出 - 用正则表达式解析HTML是不明智的。

第二:如前所述,问题中的正则表达式是无法读取。我冒着重新格式化的自由。这里是一个工作脚本包括一个注释可读版本完全相同的正则表达式:

<?php // test.php Rev:20120830_1300 
$re = '% 
    # Match a non-nested "{block:name:func(params)}...{/block:name}" structure. 
    (?P<opening>      # $1: == $opening: BLOCK start tag. 
     {        # BLOCK tag opening literal "{" 
     (?P<inverse>[!])?    # $2: == $inverse: Optional "!" negation. 
     block:       # Opening BLOCK tag ident. 
     (?P<name>[a-z0-9\s_-]+)   # $3: == $name: BLOCK element name. 
     (        # $4: Optional BLOCK function. 
     :        # Function name preceded with ":". 
     (?P<function>[a-z0-9\s_-]+) # $function: Function name. 
     (       # $5: Optional function parameters. 
      [\s]?      # Allow one whitespace before (params). 
      \(       # Literal "(" params opening char. 
      (?P<params>[^)]*)   # $6: == $params: function parameters. 
      \)       # Literal ")" params closing char. 
     )?       # End $5: Optional function parameters. 
    )?        # End $4: Optional BLOCK function. 
     }        # BLOCK tag closing literal "}" 
    )         # End $1: == $opening: BLOCK start tag. 
    (?P<contents>      # $contents: BLOCK element contents. 
     [^{]*       # {normal) Zero or more non-"{" 
     (?:        # Begin {(special normal*)*} construct. 
     \{       # {special} Allow a "{" but only if it is 
     (?!/?block:[a-z0-9\s_-]+\}) # not a BLOCK tag opening literal "{". 
     [^{]*       # More {normal} 
    )*        # Finish "Unrolling-the-Loop" (See: MRE3). 
    )         # End $contents: BLOCK element contents. 
    (?P<closing>      # $closing: BLOCK element end tag. 
     {        # BLOCK tag opening literal "{" 
     /block:       # Closing BLOCK tag ident. 
     (?P=name)      # Close name must match open name. 
     }        # BLOCK tag closing literal "}" 
    )         # End $closing: BLOCK element end tag. 
    %six'; 

$text = file_get_contents('testdata.html'); 
if (preg_match($re, $text, $matches)) print_r($matches); 
else echo("no match!"); 
?> 

注意,附加缩进和评论让一个真正明白什么是正则表达式是试图做。我的测试表明,正则表达式没有问题,并且它可以像广告一样工作。它甚至实现了Jeffrey Friedl的高级技巧“展开循环”,所以无论谁写这个都有一些真正的正则表达式技巧。

例如由于从原来的问题采取了以下数据:

<ul>{block:menu} 
    <li><a href="{var:link}">{var:title}</a> 
{/block:menu}</ul> 

这里是从脚本输出的(正确):

''' 
Array 
(
    [0] => {block:menu} 
    <li><a href="{var:link}">{var:title}</a> 
{/block:menu} 
    [opening] => {block:menu} 
    [1] => {block:menu} 
    [inverse] => 
    [2] => 
    [name] => menu 
    [3] => menu 
    [4] => 
    [function] => 
    [5] => 
    [6] => 
    [params] => 
    [7] => 
    [contents] => 
    <li><a href="{var:link}">{var:title}</a> 

    [8] => 
    <li><a href="{var:link}">{var:title}</a> 

    [closing] => {/block:menu} 
    [9] => {/block:menu} 
) 
''' 

时可选functionparams包括在测试数据也适用。

这就是说,有几个问题我有一个问题/正则表达式:

  • 的正则表达式是混合命名和编号的捕捉组。
  • {}是元字符,应该转义(尽管PCRE能够正确地确定它们应该在这种情况下按字面解释)。
  • 目前还不清楚用户将如何使用可选捕获的组。
  • 目前还不清楚OP使用这个正则表达式的问题。