簡體   English   中英

使用Regex匹配嵌套模式(使用PHP的遞歸)

[英]Matching nested Patterns with Regex (using PHP's recursion)

我目前正在嘗試用PHP編寫一個正則表達式,該表達式可讓我匹配包含不確定嵌套的自身的特定模式。 我知道默認情況下,正則表達式無法做到這一點,但是PHP的遞歸模式( http://php.net/manual/de/regexp.reference.recursive.php )應該可以實現。

我有這樣的嵌套結構:

<a=5>
    <a=3>
        Foo
        <b>Bar</b>
    </a>
    Baz
</a>

現在,我想匹配最外層標簽的內容。 為了正確匹配第一個開始標記和最后一個結束標記,我需要PHP的遞歸項目(?R)

我嘗試了這樣的模式:

/<a=5>((?R)|[^<]|<\/?[^a]|<\/?a[a-zA-Z0-9-])*<\/a>/s

基本上表示<a=5> ,其次是以下盡可能多的,然后是</a>

  • 另一個標簽(遞歸)
  • 任何未打開標簽的字符
  • 任何開頭的標簽,后跟一個可選的斜杠,而不是一個“ a”
  • 之前帶有a,但未完成(之后還有至少1個字符)

最后2種情況可能只是一種情況[標簽不是namend“ a”],但是我聽說應該在正則表達式中避免這種情況,因為它需要環顧四周並且性能會很差。

但是,我在RegEx中看不到任何錯誤,但是它與給定的字符串不匹配。 我想要以下比賽:

    <a=3>
        Foo
        <b>Bar</b>
    </a>
    Baz

這是使用RegEx的鏈接: https : //www.regex101.com/r/lO1wA6/1

您可以使用此正則表達式來匹配所需的內容(為了方便起見,將正則表達式放在字符串文字中):

'~<a=5>(<([a-zA-Z0-9]+)[^>]*>(?1)*</\2>|[^<>]++)*</a>~'

這是上面的正則表達式的分解:

<a=5>
(
  <([a-zA-Z0-9]+)[^>]*>
  (?1)*
  </\2>
  |
  [^<>]++
)*
</a>

第一部分<([a-zA-Z0-9]+)[^>]*>(?1)*</\\2>匹配一對匹配的標記及其所有內容。 假定標簽名稱由字符[a-zA-Z0-9] 匹配結束標記</\\2>時,將捕獲標記名稱([a-zA-Z0-9]+)和向后引用。

第二部分[^<>]++與標記之外的其他任何內容匹配。 請注意,不對帶引號的字符串進行處理,因此根據您的輸入,它可能不起作用。

然后返回到例程調用,該例程遞歸地調用第一個捕獲組。 您會注意到,一個標簽可以包含0個或多個其他標簽或非標簽內容的實例。 由於正則表達式的編寫方式,最外面的<a=5>...</a>對也共享此屬性。

regex101上的演示

嘗試這個:

PHP

$re = "/(<[^\\/>]+(\\/?)>)*([^<]+)(<\\/\\w+>)*/m";
$str = "<a=5>\n <a=3>\n Foo\n <b/>Bar</b>\n </a>\n Baz\n</a>";

preg_match_all($re, $str, $matches);
var_dump($matches);
// here  

 $matches[1];  //for open tag array
 $matches[2];  //for single tag mark array by ( />)
 $matches[3];  //for inner data array
 $matches[4];  //for close tag array

產量

array (size=5)
  0 => 
    array (size=5)
      0 => string '<a=5>
 ' (length=7)
      1 => string '<a=3>
 Foo
 ' (length=12)
      2 => string '<b/>Bar</b>' (length=11)
      3 => string '
 </a>' (length=6)
      4 => string '
 Baz
</a>' (length=10)
  1 => 
    array (size=5)
      0 => string '<a=5>' (length=5)
      1 => string '<a=3>' (length=5)
      2 => string '<b/>' (length=4)
      3 => string '' (length=0)
      4 => string '' (length=0)
  2 => 
    array (size=5)
      0 => string '' (length=0)
      1 => string '' (length=0)
      2 => string '/' (length=1)
      3 => string '' (length=0)
      4 => string '' (length=0)
  3 => 
    array (size=5)
      0 => string '
 ' (length=2)
      1 => string '
 Foo
 ' (length=7)
      2 => string 'Bar' (length=3)
      3 => string '
 ' (length=2)
      4 => string '
 Baz
' (length=6)
  4 => 
    array (size=5)
      0 => string '' (length=0)
      1 => string '' (length=0)
      2 => string '</b>' (length=4)
      3 => string '</a>' (length=4)
      4 => string '</a>' (length=4)

現場演示

要么

    $re = "/(<[^\\/>]+\\/?>)*([^<]+)(<\\/\\w+>)*/m";
    $str = "<a=5>fff\n <a=3>\n Foo\n <b/>Bar</b>\n </a>\n Baz\n</a>";

    preg_match_all($re, $str, $matches);
    //var_dump($matches);
    $md="";
    $c=count($matches[1]);
    foreach($matches[1] as $k=>$v){
        if($k!=0){
            $md.=$v.$matches[2][$k].$matches[3][$k];
        }
        else if ($c!=$k+1){
            $md.=$matches[2][$k].$matches[3][$k];
        }
    }   
var_dump($md);

生活

產量

 string 'fff
 <a=3>
 Foo
 <b/>Bar</b>
 </a>
 Baz
</a>' (length=44)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM