我有这个正则表达式模式:
/(?J){% *(?P<tag>[a-zA-Z_]+) *(?P<args>[a-zA-Z0-9 _-]+) *%}(?P<block>.*){% *end(?P<tag>[a-zA-Z_]+) *%}/s
这个搜索字符串:
{% import add %}{% endimport %}
{% extends base.html %}{% endextends %}
{% block title %}
Changed
{% endblock %}
{% block content %}
Yay!
{% endblock %}
通过preg_match_all
运行时,它会返回完整的搜索字符串,而不是第一个{% import add %}{% endimport %}
。为什么,我该如何解决?
答案 0 :(得分:0)
您有一个命名模式:(?P<block>.*)
。
将其更改为(?P<block>.*?)
(在明星后添加?
。)
一般注释:.*
(贪婪版本)等模式应与
非常小心,因为他们可能会消耗太多远。
您还可以对正则表达式进行进一步改进:
(?P<tag>[a-zA-Z_]+)
的第二个实例更改为(?P=tag)
- a
对第一次使用的tag
组的反向引用。
我假设在end
之后应该有相同的文字,
它捕获了第一个tag
组。(?J)
,因为没有多次出现任何命名模式
更多。(?P<args>[a-zA-Z0-9 _-]+)
更改为
(?P<args>[a-zA-Z0-9\. _-]+)
(将字面点添加到允许的集合中
字符)。
或者将允许的字符列表更改为[^%]
。
那么这个模式也会匹配
{% extends base.html %}{% endextends %}
(样本的第一行)。答案 1 :(得分:0)
正则表达式是&#34;贪心&#34;默认情况下 - 他们采用最长匹配,而不是最短。
在这种情况下,您的问题似乎是.*
令牌,它基本上转换为&#34;匹配任何内容&#34;。这将通过立即匹配字符串的整个剩余部分,然后反向跟踪来操作,直到可以满足正则表达式的后续部分。结果是,最后一个{% something %}
标记的所有内容都被视为您的最终匹配。
对此最简单的解决方案是使用.*?
,这意味着&#34;匹配任何东西,但不要贪图它#34;。这将从没有匹配开始,然后向前工作,直到模式可以匹配,可能会给你你想要的结果。
但是,正如评论中所述,标记化解析器可能更适合此类任务:跟踪字符串,将其分为标记序列,非标记,标记,非标记,然后匹配之后的标签。这将使您的语法更加灵活,并且可以减少嵌套标签等复杂性或检测格式错误的输入的麻烦。