我试图找出如果使用preg_match不存在另一个语句时如何捕获一个语句。
示例文字:
<!-- InstanceBeginEditable name="doctitle" -->
<title>BU Libraries | Research Guides | Citing Your Sources</title>
<!-- InstanceEndEditable -->
<div id="standardpgt"><h1><!-- InstanceBeginEditable name="pagetitle" --><strong>Citing Your Sources</strong><!-- InstanceEndEditable --></h1></div>
因为存在pagetitle我想拉取它而不是doctitle标签。当然,它们之间还有很多其他角色,但我想向你展示一些小样本。
如果pagetitle不存在,我想获取doctitle的内容。
扭曲的是我没有直接使用php代码,我通过配置文件传递一个正则表达式语句,然后脚本正在接受它并从语句中拉出第一组。
这就是我提出的:
((?!.*?<!--\s*?InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->.*?<!--\s*?InstanceEndEditable\s*?-->)<!--\s*?InstanceBeginEditable\s*?name=\x22doctitle\x22\s*?-->\s*?<title>(.*?)<\/title>\s*?<!--\s*?InstanceEndEditable\s*?-->|<!-- InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->(.*?)<!--\s*?InstanceEndEditable\s*?-->)
问题是由于某种原因,如果它不起作用,php总是将第一个空组读取为组1。
例如,在上面的示例文本中,它将返回
0 -> <!-- InstanceBeginEditable name="pagetitle" --><strong>Citing Your Sources</strong><!-- InstanceEndEditable -->
1 ->
2 -> <strong>Citing Your Sources</strong>
我不能为生活弄清楚如何使这项工作。我也写了这个正则表达式:
(?(?=.*?<!--\s*?InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->.*?<!--\s*?InstanceEndEditable\s*?-->).*?<!-- InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->(.*?)<!--\s*?InstanceEndEditable\s*?-->|.*?<!--\s*?InstanceBeginEditable\s*?name=\x22doctitle\x22\s*?-->\s*?<title>(.*?)<\/title>\s*?<!--\s*?InstanceEndEditable\s*?-->)
但这也不起作用。非常感谢您的帮助。
克里斯
答案 0 :(得分:6)
只需在整个表达式周围使用分支重置模式:(?| ...),如:
((?|(?!.*?<!--\s*?InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->.*?<!--\s*?InstanceEndEditable\s*?-->)<!--\s*?InstanceBeginEditable\s*?name=\x22doctitle\x22\s*?-->\s*?<title>(.*?)<\/title>\s*?<!--\s*?InstanceEndEditable\s*?-->|<!-- InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->(.*?)<!--\s*?InstanceEndEditable\s*?-->))s
来自“man perlre”:
“(|图案)” 这是“分支重置”模式,具有特殊性 捕获缓冲区的属性 编号从相同的起点开始 在每个交替分支。它可以从 perl 5.10.0。
捕获缓冲区从左到右编号,但是 在这个构造里面编号是 为每个分支重新启动。
每个分支内的编号将正常,任何 遵循此构造的缓冲区将 编号好像构造一样 只包含一个分支,即包含分支的分支 大多数捕获缓冲区。
当您想要捕获一个时,此构造将非常有用 许多替代比赛。
考虑以下模式。数字 下面显示哪个缓冲区 捕获的内容将被存储。
# before ---------------branch-reset----------- after / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x # 1 2 2 3 2 3 4
答案 1 :(得分:1)
user178551在推荐使用分支重置构造时绝对正确。您的原始正则表达式基本上没有任何问题(除了它超过300个字符并且 ALL ON ONE LINE! - 并且它无法将两个替代品中的一个放入单一捕获组)。像这样的一个非平凡的(温和的)正则表达式需要用自由间距模式写入缩进,这样你才能真正读取它。这是你的原始正则表达式,添加了一些合理的空格:
$re_OP1 = '%
( # $1:
(?!
.*?<!--\s*?InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->
.*?<!--\s*?InstanceEndEditable\s*?-->
)
<!--\s*?InstanceBeginEditable\s*?name=\x22doctitle\x22\s*?-->\s*?
<title>(.*?)<\/title>\s*? # $2:
<!--\s*?InstanceEndEditable\s*?-->
| <!-- InstanceBeginEditable\s*?name=\x22pagetitle\x22\s*?-->
(.*?) # $3;
<!--\s*?InstanceEndEditable\s*?-->
)
%six';
现在看一下这个正则表达式,你可以看到你在OR运算符的行上硬编码了一个空格(即|<!-- InstanceBegin...
)。这将导致正则表达式无法与应用的'x'
修饰符匹配。所以用\s*
替换这个空间并在测试数据上运行它,这是我得到的结果(php-5.2.14):
Array
(
[0] => <!-- InstanceBeginEditable name="pagetitle" --><strong>Citing Your Sources</strong><!-- InstanceEndEditable -->
[1] => <!-- InstanceBeginEditable name="pagetitle" --><strong>Citing Your Sources</strong><!-- InstanceEndEditable -->
[2] =>
[3] => <strong>Citing Your Sources</strong>
)
这些结果与您发布的结果类似(但由于某种原因,您的结果只显示了2个捕获组???)我们现在需要做的就是应用user178551的分支重置建议,正则表达式解决方案变为:
$re_jmr = '%
(?| # Branch reset construct. (restart counting for each alternative)
(?!
.*?<!--\s*InstanceBeginEditable\s*name="pagetitle"\s*-->
.*?<!--\s*InstanceEndEditable\s*-->
)
<!--\s*InstanceBeginEditable\s*name="doctitle"\s*-->\s*
<title>(.*?)<\/title>\s* # $1: Group 1A
<!--\s*InstanceEndEditable\s*-->
| <!--\s*InstanceBeginEditable\s*name="pagetitle"\s*-->
(.*?) # $1: Group 1B
<!--\s*InstanceEndEditable\s*-->
)
%six';
我已经将所有懒惰的\s*?
变为贪婪(因为贪婪是你想要的)。我还将所有\x22
更改为"
- 更短且更易读的恕我直言。以下是运行这个新的分支重置正则表达式的结果:
Array
(
[0] => <!-- InstanceBeginEditable name="pagetitle" --><strong>Citing Your Sources</strong><!-- InstanceEndEditable -->
[1] => <strong>Citing Your Sources</strong>
)
这是(如果我没有记错的话),正是你要找的。 (你没有提供其他替代方案的测试用例,因此尚未经过测试。)除此之外,你的原始正则表达式非常接近。