2

我想要做的是用某些html块替换用户插入的文本(比如博客文章)中的“函数”,但在“函数”中使用选项/值对。清除?不?!这么想:) 这是一个例子:

Some text, can be long, may be short, a nice story, or just a comment.
{{function option1="value1" option2="value2"}}
And some more text!
{{function2 option1="value1" option2="value2"}}

在文本中,我想替换和解析{{function ...}}部分。一个更具体的例子可能是:

{{youtube videokey="_VIDEOKEY_"}}

应该由 youtube 嵌入代码替换:

<iframe width="420" height="315" src="http://www.youtube.com/embed/_VIDEOKEY_" frameborder="0" allowfullscreen></iframe>

为此,我想使用该preg_replace_callback()函数,因此我可以有一些空间对传递的数据/选项进行一些计算。


{{ ... }}问题:我可以获取和替换这样

我尝试了很多表达方式,我认为最接近的一种是:

\{\{\w+([[:space:]]+(([0-9a-zA-Z]+)=\"([0-9a-zA-Z]+)\"))+\}\}

如您所见,我尝试匹配:

  1. {{和内的一个字符串}}
  2. 其中第一部分是一个词
  3. 后跟一个或多个选项/值对:
    • 一个或多个空格
    • 一个或多个字母或数字(选项名称)
    • =标志_
    • 一个或多个字母或数字,由"(选项值)括起来

在示例中,上面的文本将匹配(使用 preg_match_all):

array(5) (
    0 => array(2) (
        0 => string(46) "{{function option1="value1" option2="value2"}}"
        1 => string(47) "{{function2 option1="value1" option2="value2"}}"
    )
    1 => array(2) (
        0 => string(17) " option2="value2""
        1 => string(17) " option2="value2""
    )
    2 => array(2) (
        0 => string(16) "option2="value2""
        1 => string(16) "option2="value2""
    )
    3 => array(2) (
        0 => string(7) "option2"
        1 => string(7) "option2"
    )
    4 => array(2) (
        0 => string(6) "value2"
        1 => string(6) "value2"
    )
)

当使用 preg_replace_callback 和这个正则表达式时,我当然会收到相同的匹配集(在一维数组中)。


我有这个解决方案,但不喜欢它(因为它涉及正则表达式匹配的正则表达式,而我认为应该可以在一个表达式中做到这一点):

$input = ... // see text above
$output = preg_replace_callback('@\{\{\w+([[:space:]]+(([0-9a-zA-Z]+)=\"([0-9a-zA-Z]+)\"))+\}\}@', 'my_replace_function', $input);

function my_replace_function($match) {
    preg_match_all('@([0-9a-zA-Z]+)=\"([0-9a-zA-Z]+)\"@', $match[0], $matches);
    // do something with the $matches
}

甚至可以向我的回调函数传递一个包含所有选项/值对的数组,而不仅仅是最后一个匹配项,并使用该数据来解析字符串?如果是这样,你能指出我正确的方向吗?

基本上问题是:我可以在比赛中分离重复的子模式吗?


---Edit--- The solution proposed above (capturing the whole 'function'-block, then match the option-value pairs within the matched string) is in fact the solution to this puzzle. For more detail please see the answer of @m.buettner below (the accepted one).

4

1 回答 1

2

You can't. Sorry, but it's that simple. Most regex engines do not support capturing multiple values with a single capturing group. Which is equivalent to say, most regex engine support only a finite and fixed number of captures. .NET is the big exception here. But you are using PCRE - and PCRE will always return the last capture for each group (see here, official citation pending; but google for "PCRE repeated capturing group", all sources agree). And the number if groups is fixed by the number of parentheses in your pattern. Sometimes there are possible work arounds, where you transform your repeated captures into repeated matches, but I think that is not applicable either in your case.

So your solution is really the right way to go about it. You match the whole {{...}} block, and then parse out the key-value pairs within the callback separately.

于 2012-12-03T17:11:09.473 回答