1

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

我的代码:

$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

那么我是否正确地说我需要提供一个结束分隔符或其他东西?

谢谢,克里斯蒂安

4

2 回答 2

1

显然你的正则表达式匹配fname}Default{/fname} {lname而不是Default.

正如我在这里提到的,使用{(.*?)}而不是{(.*)}.

{在正则表达式中具有特殊含义,因此您应该对其进行转义\\{

而且我建议使用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
于 2012-10-10T20:30:29.650 回答
1

您的正则表达式锚定到字符串的末尾,因此您的关闭{/whatever} 必须是字符串中的最后一件事。此外,由于您的开始和结束标签是简单.*的,因此没有任何内容可以确保它们匹配。您想要的是确保您的结束标签与您的开始标签匹配 - 使用类似的反向引用{(.+)}(.*?){/\1}将确保它们相同。

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

于 2012-10-10T20:51:21.080 回答