我在PHP中使用可能为空的反向引用的正则表达式时遇到问题。我希望它能像http://www.regular-expressions.info/brackets.html中所解释的那样工作:
如果没有使用反向引用 特殊匹配尝试(例如 问题的第一个例子 马克做了第一个反向引用 它是空的。运用 正则表达式中的空反对是 非常好。它就是这样 取而代之的是虚无。
然而,似乎PHP与http://php.net/manual/en/regexp.reference.back-references.php:
有点不同如果子模式实际上没有 用于特定的比赛,然后任何 对它的反向引用总是失败。
作为一个简单的例子,我希望将以下两个内容与此正则表达式匹配:
提前知道“某事”的地方,“其他”可以是任何事物(或什么都不是)。
所以我尝试了以下正则表达式(“else”硬编码以简化):
preg_match("/\{(something(:else)?)\}(.*?)\{\/something\\2\}/is", $data, $matches)
不幸的是如果(:else)?不匹配,\ 2反向引用失败。如果我使\ 2可选(\ 2?),那么我可能会匹配{something} ... {something:else},这是不好的。
我是否遇到了正则表达式的限制(臭名昭着的“你需要一个解析器,而不是一个正则表达式”)或者这是否可以修复?
测试程序:
<?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);
?>
答案 0 :(得分:2)
更改
"/\{(something(:else)?)\}(.*?)\{\/something\\2\}/is"
要
"/\{(something(:else|))\}(.*?)\{\/something\\2\}/is"
这样一直会捕获引用,但它有时会为空(这没关系)......
答案 1 :(得分:1)
为什么不简单地使用\ 1代替\ 2?
preg_match_all("/\{(something(:else)?)\}(.*?)\{\/\\1\}/is", $data, $matches);
对于“你需要一个解析器”问题,你需要/它需要它来解析嵌套的构造。
答案 2 :(得分:0)
在这类案件的下一课(如 {something} ... {/ something}或{something} ... {something} ... {/ something} {/ something} 和更多。 SL5_ preg_contentFinder 类
的示例https://gist.github.com/sl5net/7029093#file-sl5_preg_contentfinder-php
$content1 = $content = '`ha <!--[01.o0]-->1<!--[/01.o0]-->
嗨[02.o0] 2 浩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'];
}