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>

これは問題なく機能しますが、ブロックタグの3番目の部分が導入され{block:menu:thirdbit}た場合、たとえば、一致しません。ただし、正規表現の端を切り取って次の部分に切り詰めると、一致します。これ、パターンがOKであることを意味します。他の何かがうまくいかなかった:

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

何が悪いのか考えてみませんか?

4

2 に答える 2

1

最初にティムが正しく指摘したように、HTMLを正規表現で解析するのは賢明ではありません。

2 番目: 提示されているように、質問の正規表現は読み取り不能です。私はそれを再フォーマットする自由を取りました。これは、まったく同じ正規表現のコメント付きの読み取り可能なバージョンを含む作業スクリプトです。

<?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 の高度な「Unrolling-the-Loop」効率化手法も実装されているため、これを書いた人は本物の正規表現スキルを持っています。

たとえば、元の質問から取得した次のデータがあるとします。

<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}
)
'''

functionオプションのandparamsがテスト データに含まれている場合にも機能します。

とはいえ、質問/正規表現にはいくつかの問題があります。

  • 正規表現は、名前付きのキャプチャ グループと番号付きのキャプチャ グループを混在させています。
  • {とはメタ文字であり、}エスケープする必要があります (ただし、この場合、PCRE は文字どおりに解釈する必要があると正しく判断できます)。
  • オプションでキャプチャされたグループをユーザーがどのように使用するかは不明です。
  • OPがこの正規表現を使用する際にどのような問題を抱えているかは不明です。
于 2012-08-30T19:55:55.933 に答える
1

アイデア: すべて{block:menu}の類似の要素を独自の名前空間の XML 要素に置き換えます。その後、xpath を使用でき、作業は完了です。その場でそれを行うことさえできるはずです。

于 2012-08-30T16:12:09.480 に答える