这是一个棘手的问题,我没有发现任何明确的迹象表明这是否可行; 匹配从起点指示到行尾(一行匹配)的所有内容(包括),除非在另一个起点之前有一个终点指示,在这种情况下匹配所有内容并包括它(多行匹配) )
假设我们有$ str =
blah blah begin 12345
bleh bleh
begin test
我们可以轻松匹配,例如使用begin 12345
删除preg_replace('@begin(.*?)@i', "", $str);
,向我们提供结果:
blah blah
bleh bleh
如果我们改为$ str =
blah blah begin 12345
bleh finish bleh begin test
我们还可以使用begin
轻松删除finish
和preg_replace('@begin(.*?)finish@is', "", $str);
之间的所有内容,并向我们提供结果blah blah bleh begin test
以这种方式使用s
选项,我们可以轻松地匹配 整行或多行。但是,如果找不到finish
,那么我们该如何匹配单行,直到另一个begin
,否则多行包括begin
和finish
所以,例如,如果你有$ str:
1 begin 2
3 begin 4
5 finish 6
7 finish 8
9 begin 10
如何使用单个preg_replace()删除begin(.*?)(finish)?
之类的内容以获得以下预期输出?
1
3 6
7 finish 8
9
请注意3
仍然存在,因为第一个“begin
- 超越”匹配并非贪婪,但5
被删除,因为finish
来自另一个begin
1}}。但7 finish
仍然存在,因为它没有begin
ning。这甚至可能吗?
答案 0 :(得分:2)
这完全有可能,但有点棘手 - 您可以使用以下正则表达式实现此目的:begin(?s)((?!finish|begin).)*finish|begin(?-s).*
。
让我们来看看正则表达式。它使用替换,其中第一个替代匹配所有场合,其中begin
符合结束finish
,使用tempered greedy token和内联单线修改器。第二种方法匹配剩余的begin
并删除单行模式。
begin
- 匹配字符串begin
(?s)
- 在((?!finish|begin).)*
- 匹配任何未开始的字符数begin
或finish
finish
- 匹配字符串finish
|
- 开始更改begin
- 匹配刺痛begin
(因此尚未匹配的所有begin
)(?-s)
- 关闭单线模式.*
- 匹配该行的提醒请参阅demo
驯化贪婪的代币并不是非常有效,因为必须检查每一个字符的前瞻,但我们可以控制它以提高效率。由于注册版本在第一次交替中使用了否定的字符类并且没有更多的点匹配,我们也可以删除内联修饰符。
begin(?:[^bf]*(?:(?:b(?!egin)|f(?!inish))[^bf]*)*)finish|begin.*
[^bf]*
- 匹配任意数量的字符,既不是b
也不是f
(?:b(?!egin)|f(?!inish))[^bf]*+)*
- 匹配b
或f
不属于不需要的字词,然后是其他非bf
字符 - 重复零次或多次。*+
,以避免不必要的回溯到不匹配案例的模式。另一个demo