我正在尝试匹配一个可能嵌套的模式。
下面是一些示例数据,我想在其中提取{{ loop ... }元素中的内容:
<ul>
{{ loop #users as #u }}
<li>{{ #u.first_name }} {{ #u.last_name }}</li>
{{ endloop }}
</ul>我用这个RegEx正确地理解了它:
/{{\s+loop\s+#([a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z0-9_]+)*)\s+as\s+#([a-zA-Z_][a-zA-Z0-9_]*)\s+}}(.*){{\s+endloop\s+}}/sU解释:
/{{启动\s+loop\s+ 循环关键字#([a-zA-Z_][a-zA-Z0-9_]*)变量名(例如:#var)((?:\.[a-zA-Z0-9_]+)*)可选变量键(例如:#var__.key)\s+as\s+ as关键字#([a-zA-Z_][a-zA-Z0-9_]*)\s+别名变量名(ex:#alias)
}}端(.*)循环内容{{\s+endloop\s+}}闭环元件/sU失败的地方
使用嵌套循环,我需要获得第一级循环的内容(因为内容随后在我的项目中被递归地解析)。以下是一些示例数据:
1| <ul>
2| {{ loop #users as #u }}
3| <li>
4| {{ #u.first_name }} {{ #u.last_name }}
5| <ul>
6| {{ loop #u.friends as #f }}
7| <li>{{ #f.first_name }} {{ #f.last_name }}</li>
8| {{ endloop }}
9| </ul>
10| </li>
11| {{ endloop }}
12| </ul>
13|
14| {{ loop #foo as #bar }}
15| <a href="#">{{ #bar }}</a>
16| {{ endloop }}使用此内容,模式将在遇到的第一个{{ endloop }} (2-8行)停止。
如果删除U标志(不贪婪),就不能使用多个循环,因为即使它们是不同的循环(2-16行),它也会停止到最后一个循环。
我有一个使用/m标志(multiline)的以前版本的模式,但是它也失败了,因为它只匹配最深级别的循环(行6-8)。
我做了很多次尝试(大部分是在regexr.com上做的),但没有看到任何进展。我寻找一个关于“递归模式”的解决方案,我找到的最好的解决方案是这个问题,但经过多次尝试,我无法使它适应我的项目。
(?R)的递归,但是没有成功地使用它,这对我的情况有帮助吗?我不仅仅是在寻找解决方案,我真的很想了解我如何解决这个问题。链接到当前RegexR:https://regexr.com/426fd
发布于 2018-10-31 09:08:57
下面是您当前模式的快速修复:
{{\s+loop\s+#([a-zA-Z_]\w*)((?:\.\w+)*)\s+as\s+#([a-zA-Z_]\w*)\s*}}((?:(?!{{\s+(?:end)?loop\s).|(?R))*){{\s+endloop\s+}}注意,此模式不需要U修饰符来按预期运行,但仍然需要.的s修饰符来匹配任何字符。
主要的区别在于用.*代替(?:(?!{{\s+(?:end)?loop\s).|(?R))*。它匹配0次或多次重复:
(?!{{\s+(?:end)?loop\s). -没有启动符合以下模式的序列的任何字符(.):{{ -一个{{子字符串\s+ - 1+白空间(?:end)? -一个可选的end子字符串loop -一个loop子字符串\s -一个空白
| -或(?R) -整个正则表达式此外,如果不使用[a-zA-Z0-9_]修饰符或(*UCP) PCRE动词,则\w等于u,因此整个模式可以缩短一点。
发布于 2018-10-31 09:20:15
下面是针对您的问题的性能修正(它需要几百个步骤而不是邪恶的上千个回溯步骤):
{{\s+loop\s+#(\w+)[^#]*#(\w+)\s*}}(?:[^{]*+|(?R)|{+)*{{\s+endloop\s+}}请参阅现场演示
RegExp细分:
{{\s+loop\s+#(\w+)[^#]*#(\w+)\s*}}匹配起始循环结构并捕获散列单词(?:非捕获组的启动[^{]*+除了拥有一个{之外,任何东西都匹配|或(?R)递归整个模式|或{+匹配任意数量的开口大括号
)*{{\s+endloop\s+}}匹配结束结构https://stackoverflow.com/questions/53079213
复制相似问题