使用字符串开头和可选结尾的正则表达式多 AND/OR 单行匹配
Regex multi- AND/OR single-line match using a string beginning and optional ending
这是一个棘手的问题,我还没有找到任何明确的迹象表明这是否可行; 匹配从起点指示到行尾的所有内容(包括在内)(单行匹配),除非在另一个起点之前有一个终点指示,在这种情况下,匹配直到并包括它的所有内容(多行匹配)行匹配)
假设我们有 $str =
blah blah begin 12345
bleh bleh
begin test
我们可以轻松匹配,例如使用 preg_replace('@begin(.*?)@i', "", $str);
删除 begin 12345
,得到结果:
blah blah
bleh bleh
如果我们改为 $str =
blah blah begin 12345
bleh finish bleh begin test
我们还可以使用 preg_replace('@begin(.*?)finish@is', "", $str);
轻松删除 begin
和 finish
之间的所有内容,得到结果 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
-and-beyond”匹配是非贪婪的,但 5
被删除,因为 finish
出现在另一个之前begin
。但是 7 finish
仍然存在,因为它没有 begin
ning。这甚至可能吗?
这是完全可行的,但有点棘手 - 您可以使用以下正则表达式来实现:begin(?s)((?!finish|begin).)*finish|begin(?-s).*
.
让我们看一下正则表达式。它使用交替,其中第一个替代匹配所有场合,其中 begin
遇到结束 finish
,使用 tempered greedy token 和内联单行修饰符。第二种选择匹配剩余的 begin
s 并删除单行模式。
begin
- 匹配字符串 begin
(?s)
- 打开单行模式
((?!finish|begin).)*
- 匹配不以 begin
或 finish
开头的任意数量的字符
finish
- 匹配字符串 finish
|
- 开始交替
begin
- 匹配字符串 begin
(因此所有尚未匹配的 begin
)
(?-s)
- 关闭单行模式
.*
- 匹配行 的提醒
见demo
Tempered greedy tokens 不是很有效,因为必须检查每个字符的前瞻性,但我们可以加入它以提高效率。由于注册版本使用否定字符 类 并且在第一个交替中不再使用点匹配,我们也可以删除内联修饰符。
begin(?:[^bf]*(?:(?:b(?!egin)|f(?!inish))[^bf]*)*)finish|begin.*
[^bf]*
- 匹配任意数量的字符,既不是 b
也不是 f
(?:b(?!egin)|f(?!inish))[^bf]*+)*
- 匹配不属于不需要的单词的 b
或 f
,后跟其他非 bf
字符 - 重复零次或多次。
- 内部有一个所有格修饰符
*+
以避免对不匹配情况的模式进行不必要的回溯。
另一个demo
这是一个棘手的问题,我还没有找到任何明确的迹象表明这是否可行; 匹配从起点指示到行尾的所有内容(包括在内)(单行匹配),除非在另一个起点之前有一个终点指示,在这种情况下,匹配直到并包括它的所有内容(多行匹配)行匹配)
假设我们有 $str =
blah blah begin 12345
bleh bleh
begin test
我们可以轻松匹配,例如使用 preg_replace('@begin(.*?)@i', "", $str);
删除 begin 12345
,得到结果:
blah blah
bleh bleh
如果我们改为 $str =
blah blah begin 12345
bleh finish bleh begin test
我们还可以使用 preg_replace('@begin(.*?)finish@is', "", $str);
轻松删除 begin
和 finish
之间的所有内容,得到结果 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
-and-beyond”匹配是非贪婪的,但 5
被删除,因为 finish
出现在另一个之前begin
。但是 7 finish
仍然存在,因为它没有 begin
ning。这甚至可能吗?
这是完全可行的,但有点棘手 - 您可以使用以下正则表达式来实现:begin(?s)((?!finish|begin).)*finish|begin(?-s).*
.
让我们看一下正则表达式。它使用交替,其中第一个替代匹配所有场合,其中 begin
遇到结束 finish
,使用 tempered greedy token 和内联单行修饰符。第二种选择匹配剩余的 begin
s 并删除单行模式。
begin
- 匹配字符串begin
(?s)
- 打开单行模式((?!finish|begin).)*
- 匹配不以begin
或finish
开头的任意数量的字符
finish
- 匹配字符串finish
|
- 开始交替begin
- 匹配字符串begin
(因此所有尚未匹配的begin
)(?-s)
- 关闭单行模式.*
- 匹配行 的提醒
见demo
Tempered greedy tokens 不是很有效,因为必须检查每个字符的前瞻性,但我们可以加入它以提高效率。由于注册版本使用否定字符 类 并且在第一个交替中不再使用点匹配,我们也可以删除内联修饰符。
begin(?:[^bf]*(?:(?:b(?!egin)|f(?!inish))[^bf]*)*)finish|begin.*
[^bf]*
- 匹配任意数量的字符,既不是b
也不是f
(?:b(?!egin)|f(?!inish))[^bf]*+)*
- 匹配不属于不需要的单词的b
或f
,后跟其他非bf
字符 - 重复零次或多次。- 内部有一个所有格修饰符
*+
以避免对不匹配情况的模式进行不必要的回溯。
另一个demo