【问题标题】:regex, php, and the evil nested (?R)正则表达式、php 和邪恶的嵌套 (?R)
【发布时间】:2012-02-09 23:24:40
【问题描述】:

更新

所以我仍然在搞砸这个,并且已经找到了所有标签的实例,虽然我宁愿只找到最深的堆叠实例,因为那样生活会更轻松..无论如何这就是我得到..

/(({{)(?:(?=([^\/][^ ]*?))\3|(\/[\w])))([a-zA-Z0-9\$\'\"\s\#\%\^\&\!\.\_\+\=\-\\\*\(\)\ ]+?}})/

是否有任何正则表达式大师可以给我一些指示或模仿我需要的正则表达式?这只会获得像这样结束的 {{tag}} 的最深堆叠实例 {{//tag}}

原创

好的,所以我有一个问题,我看到其他人也有,但是用不同的方法解决它。或者我是这么想的。所以我很好奇是否有其他人可以帮助我进一步解决这个问题。

我有一个充满模板的数据库,我需要在 PHP 中使用这些模板,这些模板是由另一个系统制作和使用的,因此无法更改。话虽如此,这些模板都添加了层次样式标签。我需要做的是从数据库中获取这些模板,然后以编程方式查找这些标签、它们的函数名称(或标签名称)及其内部内容,以及括号内函数(标签)名称后面的任何内容。 . 这些标签之一的示例是,{{FunctionName some (otherStuff) !Here}} 一些内容位于其中并以 {{/FunctionName}}

结尾

这是它变得更有趣的地方,模板有另一个随机标签,我猜这是这些标签的“可变”样式,因为它们通常是相同的语法。看起来像这样,${RandomTag},但有时函数样式存在但没有结束标记,就像这样.. {{RandomLoner}}

示例模板...

{{FunctionTag (Condition?)}}
    <div>This is an {{CheckOfSomeSort someTimesThese !orThese}}
        example of some {{Random}} data
    {{/CheckOfSomeSort}} that will be ${worked} on</div>
{{/FunctionTag}}

好吧,这绝不是一个真正的模板,但它遵循我迄今为止看到的所有规则。

现在我用 regex 和 preg_match_all 尝试了不同的方法来提取匹配项,并将它们中的每一个放入一个不错的数组中。到目前为止,我得到的是这个(在示例模板上使用它以确保它仍然工作)

Array
(
    [0] => Array
        (
            [0] => {{CheckOfSomeSort someTimesThese !orThese}}example of some datas{{/CheckOfSomeSort}}
            [1] => {{CheckOfSomeSort someTimesThese !orThese}}
            [2] => CheckOfSomeSort
            [3] => example of some data
            [4] => {{/CheckOfSomeSort}}
        )
)

我尝试了几种方法,(我花了将近 8 个小时才到达)

/({{([^\/].[^ ]*)(?:.[^ ][^{{]+)}})(?:(?=([^{{]+))\3|{{(?!\2[^}}]*}}))*?({{\/\2}})/

AND, more recently...

/({{([^\/].[^ ]*)(?:.[^ ][^{{]+)}})((?:(?!\{\{|\}\}).)++|(?R)*)({{\/\2}})/

我绝不是正则表达式的专家,我实际上是在过去一天左右才学会的,试图让它发挥作用。我已经对此进行了谷歌搜索,并意识到正则表达式不是为嵌套的东西设计的,但是 (?R) 似乎可以解决我在互联网上看到的简单括号示例的技巧,但它们总是只考虑到{ 和 } 或 ( 和 ) 或 。在阅读了几乎整个 regex info 网站并玩了之后,我想出了这两个版本。

所以我需要做的(我认为),首先从 DEEPEST 层次结构标记中进行正则表达式工作,然后解决问题(如果我可以在 php 的帮助下做到这一点,那对我来说很好)。我在想找到最深的层,获取它的数据,然后向后工作,直到所有内容都在 1 个胖数组中。我以为这就是 ($R) 将为我做的事情,但事实并非如此。

因此,对我所缺少的内容的任何帮助都会很棒,还要注意我的 {{}} 似乎有问题,没有它的结尾版本。所以就像我的 {{Random}} 示例一样,为了我解析数组示例而被删除。我觉得这些标签以及 ${} 标签可以单独放置(如果我知道如何使用正则表达式来做到这一点),并且只保留在它们所在的文本中。我或多或少对这些函数感兴趣,并将它们的数据放入一个多维数组中以供我进一步使用。

很抱歉,这篇文章很长,我整晚都在用这个来敲我的脑袋。我开始假设它会更容易一些。直到我意识到嵌套的标签:/

感谢任何帮助!谢谢!

【问题讨论】:

  • 我知道这是一个禁忌(而且性能很糟糕),但如果这只是你需要完成的事情,一旦你总是可以做一个 preg_match 来获得最外面的“标签”和然后对该标签的内容进行进一步的preg_match 调用。可能比尝试创建单个整体正则表达式更容易。
  • @rdlowrey 不会为嵌套标签产生相同的结果...考虑简单的示例 {{foo}}hello world {{foo}} goodbye {{/foo}}{{/foo}}
  • 对于初学者来说,{} 在正则表达式中是特殊的,你需要将它们转义——这并不是说它有帮助,它使事情变得更加复杂:p 只是一个“旁白”。 .. 进一步阅读。
  • 另外,我认为您在上面列出的正则表达式刚刚松散,早餐吃了一些小孩
  • @Kaii 我只是想说将问题空间分解成更小、更可解决的问题可能更简单……与其说“完全做到这一点”我>。我可能应该更清楚。

标签: php regex nested hierarchy preg-match-all


【解决方案1】:

经过一段时间的研究,我最终了解了更多关于正则表达式的知识,并且现在将其理解为 T。很棒的一点是,PHP 有 (?R),我现在明白为什么它看起来像这样了。哈哈

最后,我开始工作的正则表达式产生于解释递归 (?R) 的 php 页面。然后,我只是努力让标签正则表达式代替他们在示例中使用的括号。

我知道我想要最里面的标签,但是当然可以用最外面的标签完成同样的事情,所以这个正则表达式就是这样做的。它找到并抓取最外层的 {{tag (thatMightHaveDataHere)}} 并在其中包含可能更多 {{TAGS}} 的内部内容。{{/tag}}

来了,

/{{([\w]+) ?([^}]*?)(?:}}((?:[^{]*?|(?R)|{{[\w]*?}}|\${.*?})*){{\/\1}})/ 

0 = 匹配的“外部标签” 1 = 找到的标签,即 {{tag}}{{/\1}} 2 = 第一个空格之后的任何数据,在标签内,即 {{tag ThisDataIs StoredAs2}} 3 = INNER 内容(可以是此正则表达式的递归,也可以是非结束标签 {{noEndTag}},或以美元开头的标签 ${likeThis}

使用此正则表达式在 $match[3] 上运行一个循环,您可以循环查找它们。不知道你会在我需要它之外的地方使用它,但我相信如果有人需要它来处理其他嵌套样式结构,他们可以修改它。

【讨论】:

    【解决方案2】:

    警告!您正在尝试仅使用正则表达式编写解析器。这不太好。为什么不?因为你还需要存储 state

    然后呢?好吧,你当然会写一个解析器:D

    如果您需要有关如何开始使用的任何提示,我可以提供帮助,但我鼓励您先自己尝试。解析器是如何工作的? :)


    标记您的输入。并将其转换为嵌套树,如下所示:

    array(
        array("code", "FunctionTag (Condition?)", array(
            "<div>This is an ",
            array("code", "CheckOfSomeSort someTimesThese !orThese", array(
                "example of some ",
                array("code", array("Random"), array()),
                " data"
            )),
            " that will be ${worked} on</div>"
        ))
    )
    

    现在您只需解释代码部分并产生预期的输出。您还可以添加行号和字符位置等对调试非常有用的内容。

    【讨论】:

    • 讨厌这么说,但是是的,它是一个解析器。但我写它的原因与世界其他地方的原因不同,这就是它成为问题的地方,因为它会可能只用于这种情况..在任何一种情况下,提示都会很棒..就像我列出的那样,我有这个概念,只需要弄清楚我哪里出错了..我觉得我正在使用这两种情况正确地,甚至通过一个函数运行它们以删除找到的内容..只是在它发现的第一个标签之后它不会继续..我想要所有的深层标签,而不是删除它们,退出,然后继续循环..
    【解决方案3】:

    哇,多么奇怪的模板语法。

    我可能用来解决这个问题的方法是这样的:

    • 使用简单的正则表达式将所有{{tags}} 更改为&lt;tags&gt;
    • 使用另一个简单的正则表达式将标签内以空格分隔的参数/条件转换为类似 XML 的属性语法(例如,{{foo bar !baz}} 将变为 &lt;foo arg1="bar" arg2="!baz"&gt; 或类似的)
    • 将其处理为DOMDocument

    玩得开心。 :-)

    【讨论】:

    • 嗯,我很欣赏这个建议,虽然我之前并没有真正使用过“DOMDocument”.. 猜猜一夜之间弄清楚了正则表达式之后,尽管深入研究一些新的东西不会有什么坏处: P 它确实有点吓到我,因为我不想以任何方式搞砸完整的 html,最后 html 和标记的数据需要分开..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 2019-05-17
    • 1970-01-01
    • 2011-04-23
    相关资源
    最近更新 更多