2015-02-11 34 views
2

以条件实现模板我试图实现一个管理界面,管理员可以在其中创建站点元标记形成的高级规则。如何使用preg_replace

我有一个函数,它接受一个模板并用$ registry中的值替换其中的占位符,并在需要时应用修饰符。

$registy = array('profession_name' => 'actor', 'total_found' => 100,); 

$result = preg_replace_callback('/\{([^{}:]+)(:[^{}:]+)?\}/', function($matches) use ($registry) { 

    $result = $registry[$matches[1]] ?: $matches[0]; 

    if (in_array($matches[2], array(':ucfirst', ':strtolower', ':strtoupper', ':lcfirst'))) 
    { 
     $result = call_user_func(substr($matches[2], 1), $result); 
    } 

    return $result; 
}, 
$template); 

实施例:

职业{名称:ucfirtst}是{profession_name:strtoupper}

被parced到

专业名称是ACTOR

我试图执行条件,所以这将是可能的,使这样的规则:

条件前的{placeholdes}文本。 [{total_found},包含{占位符}的TRUE文本,包含{占位符}的FALSE文本],条件后带有{占位符}的文本。

所以我的函数会从注册表中获得{total_found}值,并且根据它是真还是假会返回带有相应假或真模式的字符串。 我在正则表达式中很糟糕,无法弄清楚如何用正则表达式来编写这个条件。 请帮助我。

UPDATE: 具体的例子看起来像WHIS:

$template = 'Profession is {profession_name}. [{total_found}, {total_found} vacancies found, No vacancies found]. {profession_name} in your town'; 
在我的回调函数

我想这种地方

if ($matches[condition]) // i don't no how exactly 
    $result = $matches[true-condition]; 
else 
    $result = $matches[false-condition] 

的条件所以,如果$registry['total_found'] = 100;最终的结果将是«职业是演员。找到100个空缺。演员在你的城镇»。 如果$registry['total_found'] = 0;最终结果将是«职业是演员。找不到空缺。演员在你的城镇»。

+0

你可以给一个'$注册表'的样本吗?什么是“{total_found}”?一个字符串中的条件,一个布尔值? – 2015-02-11 15:54:25

+0

'$ registy = array( 'profession_name'=>'actor', 'total_found'=> 100, );' – 2015-02-11 16:08:56

+0

我计划在函数中检查值是否为条件的值,无论它是真还是假,是否为空,可能等于是不是。 – 2015-02-11 16:11:14

回答

1
$available_functions = array('ucfirst', 'strtolower', 'strtoupper', 'lcfirst'); 
$registry = array('profession_name' => 'actor', 'total_found' => 100,); 
$template = 'Profession {"is":strtoupper} {profession_name:strtoupper:lcfirst}. [{total_found}, {total_found} vacancies found, No vacancies found]. {profession_name} in your town'; 

$pattern = <<<'EOD' 
~ 
(?=[[{]) # speed up the pattern by quickly skipping all characters that are not 
      # a "[" or a "{" without to test the two branches of the alternation 
(?: 
    # conditional 
    \[ 
     { (?<if> [^}]+) } , 
     (?<then> [^][,]*) 
     (?:, (?<else> [^][]*))? 
    ] 
    | 
    # basic replacement 
    (?<!\[) # allow nested conditionals   
    { 
     (?<var_name> [^{}:]+) 
     (?: : (?<func_name> [^{}:]+))? # first function to apply 
     (?: (?<other_funcs> : [^}]+))? # allow to chain functions 
    } 
) 
~x 
EOD; 

$replacement = function ($m) use ($registry, $available_functions) { 
    if (!empty($m['if'])) { 
     $cond = $m['if']; 

     # when the condition doesn't exist, the string is evaluated as it 
     if (isset($registry[$cond])) 
      $cond = $registry[$cond]; 

     return $cond ? $m['then'] : $m['else']; 

    } else { 
     $value = isset($registry[$m['var_name']]) ? $registry[$m['var_name']] : trim($m['var_name'], '"\''); 

     if (isset($m['func_name'])) { 
      $func = trim($m['func_name']); 

      if (in_array($func, $available_functions)) 
       $value = call_user_func($func, $value); 
     } 

     if (isset($m['other_funcs'])) 
      return '{\'' . $value . '\'' . $m['other_funcs'] . '}'; 

     return $value; 
    } 
}; 

$result = $template; 

do { 
    $result = preg_replace_callback($pattern, $replacement, $result, -1, $count); 
} while ($count); 

echo $result; 

当条件满足时,方法包括先替换好的分支,再次在分支内部继续进行替换。这就是为什么preg_replace_callback处于do...while循环中的原因。另一个原因是允许链接功能。

请注意,除了速度和可读性的小改进之外,该模式不需要使用特殊功能。

我添加了一些改进,如默认行为(当在注册表中找不到东西时),使用链接函数和文字字符串的能力。显然你可以根据自己的需要改变它们。

+0

非常感谢。它像一个魅力! – 2015-02-13 17:21:06