2012-08-30 83 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使用這個正則表達式的問題。