空のバックレファレンスは、PHPの一致障害を引き起こします…回避策はありますか?
-
27-09-2019 - |
質問
潜在的に空の逆を使用するPHPでの正規表現に問題があります。私はそれが説明されているように機能することを望んでいました http://www. Regual-Expressions.info/brackets.html:
特定の一致の試行で背面が使用されなかった場合(質問マークが最初の背景をオプションにした最初の例など)、それは単に空です。正規表現で空の逆を使用することはまったく問題ありません。それは単に無に置き換えられます。
しかし、PHPは少し違っているようです... http://php.net/manual/en/regexp.reference.back-references.php:
Subpatternが実際に特定の一致で使用されていない場合、それへのバック参照は常に失敗します。
単純化された例として、私は次の2つのことをこのregexと一致させたいと思います。
- {何か} ... {/何か}
- {何か:else} ... {/何か:else}
「何か」が事前に知られており、「他の」は何でも(または何もない)ことができます。
それで、私は次の正規表現を試しました(「他の」シンプルさのためにハードコードされた "else):
preg_match("/\{(something(:else)?)\}(.*?)\{\/something\\2\}/is", $data, $matches)
残念ながら(:else)?一致しません、 2の背景は失敗します。 2をオプション( 2?)にすると、{何か} ... {何か:else}を一致させるかもしれません。
私は正規表現の制限に遭遇しましたか(悪名高い「あなたはregexではなくパーサーが必要です」)、またはこれは修正可能ですか?
テストプログラム:
<?php
$data = "{something} ... {/something}
{something:else} ... {/something:else}
{something:else} ... {/something}";
// won't match {something} ... {/something}
preg_match_all("/\{(something(:else)?)\}(.*?)\{\/something\\2\}/is", $data, $matches);
print_r($matches);
// change \\2 to \\2? and it matches too much
preg_match_all("/\{(something(:else)?)\}(.*?)\{\/something\\2?\}/is", $data, $matches);
print_r($matches);
?>
解決
2の代わりに 1を単に使用してみませんか?
preg_match_all("/\{(something(:else)?)\}(.*?)\{\/\\1\}/is", $data, $matches);
「パーサーが必要」の問題については、ネストされた構造を解析するためにそれを必要とします。
他のヒント
さて、なぜ置き換えてみませんか?または?
変化する
"/\{(something(:else)?)\}(.*?)\{\/something\\2\}/is"
に
"/\{(something(:else|))\}(.*?)\{\/something\\2\}/is"
そうすれば、参照は常にキャプチャされますが、時々空になります(大丈夫です)...
そのような場合のクラスに続くクラス({何か} ... {/何か}または{何か}などのように)preg_contentfinder クラス
https://gist.github.com/sl5net/7029093#file-sl5_preg_contentfinder-php
$content1 = $content = '`ha <!--[01.o0]-->1<!--[/01.o0]-->
こんにちは[02.o0] 2 ho 3 `';
$pos_of_next_search = 0;
$begin = '(<!--)?\[([^\]>]*\.o0)\](-->)?';
$end = '<!--\[\/($2)\]-->';
$cf = new SL5_preg_contentFinder($content);
$cf->setBeginEnd_RegEx($begin, $end);
$cf->setSearchMode('use_BackReference_IfExists_()$1${1}');
$loopCount = 0;
while ($loopCount++ < 5) {
$cf->setPosOfNextSearch($pos_of_next_search);
list($findPos['begin_begin'], $findPos['end_begin'],
$findPos['begin_end'], $findPos['end_next'], $matchesReturn) = $cf->get_borders_left(__LINE__);
$content = $cf->getContent();
$expectedContent = $maxLoopCount;
if ($maxLoopCount>3)$expectedContent = '';
if ($content != $expectedContent)
die(__LINE__ . 'ERROR : $content != $expectedContent :' . " '$content'!= '$expectedContent ");
if (is_null($findPos['begin_begin'])) {
break;
}
echo(__LINE__ . ': '.$content1.' ==> "' . $content . '"');
$pos_of_next_search = $findPos['end_next'];
}