如何使用 preg_replace 实现带条件的模板 [英] how to implement template with conditions with preg_replace

查看:40
本文介绍了如何使用 preg_replace 实现带条件的模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个管理界面,管理员可以在其中创建站点元标记形成的高级规则.

I'm trying to implement an admin interface where manager could create advanced rules of site meta tags formation.

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

I have a function which takes a template and replaces placeholders in it with values from $registry and applies modifiers if needed.

$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);

示例:

职业 {name:ucfirtst} 是 {profession_name:strtoupper}

Profession {name:ucfirtst} is {profession_name:strtoupper}

被分配到

职业名称是演员

我正在尝试实现条件,因此可以制定如下规则:

I'm trying to implement conditions, so it would be possible to make rules like this:

在条件前带有 {placeholders} 的文本.[{total_found},带有 {placeholders} 的 TRUE 文本,带有 {placeholders} 的 FALSE 文本],条件后带有 {placeholders} 的尾随文本.

text with {placeholdes} before condition. [{total_found}, TRUE text with {placeholders}, FALSE text with {placeholders}], trailing text with {placeholders} after condition.

所以我的函数将从注册表中获取 {total_found} 值,并且取决于它是真还是假将返回带有相应假或真模式的字符串.我非常不擅长正则表达式,无法弄清楚如何用正则表达式来写这个条件.请帮帮我.

So my function would get {total_found} value from registry and depending if it's true or false would return string with corresponding false or true-pattern. I'm very bad at regular expressions, and can't figure out how to write this condition in regexp terms. Help me please.

更新:具体的例子看起来像 whis:

UPDATE: concrete example looks like whis:

$template = 'Profession is {profession_name}. [{total_found}, {total_found} vacancies found, No vacancies found]. {profession_name} in your town';

在我的回调函数中,我会放置这样的条件

in my callback function i would place a condition like this

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

所以如果 $registry['total_found'] = 100; 最终结果将是 «Profession is actor.发现 100 个职位空缺.你所在城市的演员».如果 $registry['total_found'] = 0; 最终结果将是 «Profession is actor.没有找到空缺.你所在城市的演员».

So in case $registry['total_found'] = 100; final result would be «Profession is actor. 100 vacancies found. Actor in your town». In case $registry['total_found'] = 0; final result would be «Profession is actor. No vacancies found. Actor in your town».

推荐答案

$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 循环中的原因.另一个原因是允许链接函数.

When a condition is met, the approach consists to replace with the good branch first and to proceed to the replacement inside the branch in a second time. This is the reason why preg_replace_callback is in a do...while loop. The other reason is to allow chained functions.

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

Note that except small improvements for speed and readability, the pattern doesn't need to use special features.

我添加了一些改进,例如默认行为(当在注册表中找不到某些内容时)、使用链式函数和文字字符串的能力.您显然可以根据需要将它们更改为英尺.

I have added several improvements like default behaviors (when something is not found in the registry), the ability to use chained functions and literal strings. You can obviously change them to feet to your needs.

这篇关于如何使用 preg_replace 实现带条件的模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆