как реализовать шаблон с условиями с 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} является {профессия_имя: strtoupper}

разделено на

Профессия Имя ACTOR

Я пытаюсь реализовать условия, поэтому можно было бы сделать правила, как это:

текст с {placeholdes} до условия. [{total_found}, ИСТИНА текст с {заполнителями}, ЛОЖЬ текст с {заполнителями}], конечный текст с {заполнителями} после условия.

Таким образом, моя функция получит значение {total_found} из реестра, и в зависимости от того, будет ли оно истинным или ложным, вернет строку с соответствующим ложным или истинным шаблоном.
Я очень плохо разбираюсь в регулярных выражениях и не могу понять, как написать это условие в терминах регулярных выражений.
Помоги мне, пожалуйста.

ОБНОВИТЬ:
конкретный пример выглядит так:

$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; Конечный результат будет «Профессия актера. Вакансий не найдено. Актер в твоем городе ».

2

Решение

$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 петля. Другая причина состоит в том, чтобы разрешить цепочечные функции.

Обратите внимание, что кроме небольших улучшений в скорости и удобочитаемости, шаблон не должен использовать специальные функции.

Я добавил несколько улучшений, таких как поведение по умолчанию (когда что-то не найдено в реестре), возможность использовать связанные функции и буквенные строки. Очевидно, вы можете изменить их на ноги в соответствии с вашими потребностями.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]