尝试替换字符串,但它似乎只匹配第一次出现,如果我有另一次出现它不匹配任何东西,所以我想我需要添加某种结束分隔符?
我的代码:
$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
所以我说我需要提供结束分隔符或其他内容吗?
谢谢, 基督教
答案 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]+
),不涉及反向引用或必须明确声明您正在使用非贪婪匹配。