PHP - preg_replace不匹配多次出现

时间:2012-10-10 20:22:25

标签: php regex preg-replace

尝试替换字符串,但它似乎只匹配第一次出现,如果我有另一次出现它不匹配任何东西,所以我想我需要添加某种结束分隔符?

我的代码:

$mappings = array(
    'fname'     => $prospect->forename,
    'lname'     => $prospect->surname,
    'cname'     => $prospect->company,
);

foreach($mappings as $key => $mapping) if(empty($mapping)) $mappings[$key] = '$2';

$match  = '~{(.*)}(.*?){/.*}$~ise';
$source     = 'Hello {fname}Default{/fname} {lname}Last{/lname}';
// $source  = 'Hello {fname}Default{/fname}';

$text = preg_replace($match, '$mappings["$1"]', $source);

因此,如果我使用被评论的$ source,它匹配得很好,但是如果我使用上面代码中当前有2个匹配的那个,它就不匹配任何东西而且我得到一个错误:

Message: Undefined index: fname}Default{/fname} {lname

Filename: schedule.php(62) : regexp code

所以我说我需要提供结束分隔符或其他内容吗?

谢谢, 基督教

2 个答案:

答案 0 :(得分:1)

显然,您的正则表达式与fname}Default{/fname} {lname而不是Default匹配。

正如我所提到的,here使用{(.*?)}代替{(.*)}

{在regexp中具有特殊含义,因此您应该将其转义\\{

我建议使用preg_replace_callback代替e修饰符(您有更多的流量控制和语法高亮,并且无法强制您的程序执行恶意代码)。

您犯的最后一个错误是不检查所请求的索引是否存在。 :)

我的解决方案是:

<?php

class A { // Of course with better class name :)
    public $mappings = array(
        'fname' => 'Tested'
    );

    public function callback( $match)
    {
        if( isset( $this->mappings[$match[1]])){
            return $this->mappings[$match[1]];
        }

        return $match[2];
    }   
}

$a = new A();
$match  = '~\\{([^}]+)\\}(.*?)\\{/\\1\\}~is';
$source     = 'Hello {fname}Default{/fname} {lname}Last{/lname}';

echo preg_replace_callback( $match, array($a, 'callback'), $source);

这导致:

[vyktor@grepfruit tmp]$ php stack.php
Hello Tested Last

答案 1 :(得分:1)

您的正则表达式将锚定在字符串的末尾,因此您关闭{/whatever} 必须才能成为字符串中的最后一个内容。此外,由于您的打开和关闭标记只是.*,因此没有任何内容可以确保它们匹配。你想要的是确保你的结束标记与开始标记匹配 - 使用像{(.+)}(.*?){/\1}这样的反向引用将确保它们是相同的。

我确信那里还有其他陷阱 - 如果你能控制你正在使用的字符串格式(IE - 你正在使用自己的模板语言),我会认真考虑转向更简单的,更容易匹配格式。由于您没有“保存”默认值,因此使用封闭标记不会为您提供任何附加值,但会使解析更加复杂。只使用$VARNAME同样可以正常工作并且更容易匹配(\$[A-Z]+),不涉及反向引用或必须明确声明您正在使用非贪婪匹配。