如何使用 preg_replace 条件实现模板
how to implement template with conditions with 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);
示例:
Profession {name:ucfirtst} is {profession_name:strtoupper}
被分割成
Profession Name is ACTOR
我正在尝试实施条件,因此可以制定如下规则:
text with {placeholdes} before condition. [{total_found}, TRUE text with {placeholders}, FALSE text with {placeholders}], trailing text with {placeholders} after condition.
所以我的函数将从注册表中获取 {total_found} 值,并且根据它是真还是假将 return 字符串与相应的假或真模式。
我很不擅长正则表达式,不知道如何用正则表达式来写这个条件。
请帮助我。
更新:
具体的例子看起来像:
$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;
最终结果是 «职业是演员。没有找到职位空缺。你镇上的演员»。
$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
循环中的原因。另一个原因是允许链式函数。
请注意,除了速度和可读性方面的小幅改进外,该模式不需要使用特殊功能。
我添加了一些改进,例如默认行为(当在注册表中找不到某些内容时)、使用链式函数和文字字符串的能力。您显然可以根据需要将它们更改为脚。
我正在尝试实现一个管理界面,管理员可以在其中创建网站元标记形成的高级规则。
我有一个函数,它接受一个模板并将其中的占位符替换为 $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);
示例:
Profession {name:ucfirtst} is {profession_name:strtoupper}
被分割成
Profession Name is ACTOR
我正在尝试实施条件,因此可以制定如下规则:
text with {placeholdes} before condition. [{total_found}, TRUE text with {placeholders}, FALSE text with {placeholders}], trailing text with {placeholders} after condition.
所以我的函数将从注册表中获取 {total_found} 值,并且根据它是真还是假将 return 字符串与相应的假或真模式。 我很不擅长正则表达式,不知道如何用正则表达式来写这个条件。 请帮助我。
更新: 具体的例子看起来像:
$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;
最终结果是 «职业是演员。没有找到职位空缺。你镇上的演员»。
$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
循环中的原因。另一个原因是允许链式函数。
请注意,除了速度和可读性方面的小幅改进外,该模式不需要使用特殊功能。
我添加了一些改进,例如默认行为(当在注册表中找不到某些内容时)、使用链式函数和文字字符串的能力。您显然可以根据需要将它们更改为脚。