Задать вопрос
yaleksandr89
@yaleksandr89
PHP developer

Как заменить по шаблону значения, которые находятся в другом массиве?

Здравствуйте.
Помогите решить задачку. Дано два массива:
1) массив с данными о работнике (значения которого нужно подставить)
$user = [
    'id' => 1,
    'name' => 'Ivan Ivanov',
    'role' => 'developer',
    'salary' => 100
];

2) Массив с шаблоном для замены (куда нужно подставить)
$apiTemplatesSet1 = [
    '/api/items/%id%/%name%',
    '/api/items/%id%/%role%',
    '/api/items/%id%/%salary%'
];


Регулярку сделал такую: ~%id%/%(.+)%~. Но что-то мне она не особо нравится, так как при попытке найти по ней значения
Получается

$result = preg_match('~%id%/%(.+)%~',$apiTmpSet,$matches);

array (size=2)
  0 => string '%id%/%name%' (length=11)
  1 => string 'name' (length=4)
array (size=2)
  0 => string '%id%/%role%' (length=11)
  1 => string 'role' (length=4)
array (size=2)
  0 => string '%id%/%salary%' (length=13)
  1 => string 'salary' (length=6)



Пробовал ещё такой вариант: '~%(.+)%/%(.+)%~', массив получается из трех элементов и первым идет значение с %...%/%...%. Можно ли получить только значения между знаков вопроса?

И насчет самой замены, подскажите как правильнее сделать? Сначала хотел перебрать foreach массив $apiTemplatesSet1, получить строки и заменить по регулярке, но встал вопрос, как подставить значения из другого массива ($user)? Да и решение, как мне кажеться через чур громоздкое.

Есть ли готовые функции в php, для данной задачи? И если нет, то как лучше написать собственную?
  • Вопрос задан
  • 734 просмотра
Подписаться 3 Простой 11 комментариев
Решения вопроса 3
p00h
@p00h
Фехтовальщик-стропальщик
<?php
$user = [
    'id' => 1,
    'name' => 'Ivan Ivanov',
    'role' => 'developer',
    'salary' => 100
];

$apiTemplatesSet1 = [
    '/api/items/%id%/%name%',
    '/api/items/%id%/%role%',
    '/api/items/%id%/%salary%'
];

print_r(str_replace(array_keys($user), array_values($user), str_replace("%", "", $apiTemplatesSet1)));


Array
(
    [0] => /api/items/1/Ivan Ivanov
    [1] => /api/items/1/developer
    [2] => /api/items/1/100
)
Ответ написан
usdglander
@usdglander Куратор тега PHP
Yipee-ki-yay
Поделюсь куском кода, из класса, который сам использую в одном из проектов (это не готовый код для использования, а просто пара методов, вырезанная из контекста, но это может дать представление о том как решаются такие задачи)
/**
     * Производит заливку шаблона значениями из массива
     *
     * Литералы шаблона вида {<liter_1>.<liter_2>...} будут заменены на соотвествующие значения из массива
     * $data[<liter_1>][<liter_2>]...
     *
     * @param $template Шаблон, содержащий литералы
     * @param $data Массив значений для подстановки
     * @return string Преобразованная строка
     */
    public function fill_template($template, $data)
    {
        preg_match_all('/\{([A-Za-z0-9_\.]+)\}/u', $template, $match);
        list($snippets, $fillers) = $match;
        
        if (!empty($snippets)) {
            
            $fillers = array_map(function($filler) use ($data) {
                $keys = explode('.', $filler);
                return $this->array_find($keys, $data);
            }, $fillers);
            
            return strtr($template, array_combine($snippets, $fillers));
            
        }
        
        return $template;
    }
    
    /**
     * Рекурсивно ищет значение в массиве в порядке обозначенным $keys
     *
     * @param array $keys Массив ключей в порядке поиска их в массиве
     * @param array $data Массив значений для поиска
     * @param string $default Значение по умолчанию, если нет соответствующего значения в массиве
     * @return mixed
     */
    public function array_find($keys, $data, $default = '')
    {
        if (!is_array($data) || empty($keys)) return $data;
        
        $key = current($keys);
        return (isset($data[$key]))
            ? $this->array_find(array_slice($keys, 1), $data[$key], $default)
            : $default;
    }


$user = [
    'id' => 1,
    'name' => 'Ivan Ivanov',
    'role' => 'developer',
    'salary' => 100
];

fill_template('/api/items/{id}/{name}', $user); // /api/items/1/Ivan Ivanov


upd: соответственно под свой шаблон нужно поменять строку
preg_match_all('/\{([A-Za-z0-9_\.]+)\}/u', $template, $match);


upd2: Занудам: Да, я знаю про array_shift. :)
Ответ написан
Compolomus
@Compolomus Куратор тега PHP
Комполом-быдлокодер
$user = [
    'id' => 1,
    'name' => 'Ivan Ivanov',
    'role' => 'developer',
    'salary' => 100
];

$apiTemplatesSet1 = [
    '/api/items/%id%/%name%',
    '/api/items/%id%/%role%',
    '/api/items/%id%/%salary%'
];

class Invoker
{
    private $data;

    public function __construct(array $data)
    {
        $this->data = $data;
    }

    public function __invoke(array $key): string
    {
        return $this->data[$key[1]];
    }
}

$function = new Invoker($user);

$result = array_map(function ($key) use ($function)
{
    return preg_replace_callback('#%(.*)%#isU', $function, $key);
}
, array_values($apiTemplatesSet1));

echo '<pre>' . print_r($result, true);

https://3v4l.org/DbIAi
5e32d4911eae6354134814.png
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы