Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> sprintf , операции над аргументами 
V
    Опции темы
bars80080
Дата 27.8.2009, 17:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



вот такая вот задачка:

есть у нас функция, она принимает в себя значения формата, производит какие-то действия и наполняет результирующую строку данными, которые потом выдаёт. можно ли задать какие провести операции над этими данными?

к примеру,
есть функция, которая принимаетт такие аргументы:
Код

$r = myfunc("The %2\$s contains %1\$d monkeys. That's a nice %2\$s full of %1\$d monkeys.", array('numb', 'location'));

внутри функции происходит выборка из БД, а затем подстановка данных, где %1\$d заменяется на $row['numb'], а %2\$s на $row['location'].
итоговая строка выдаётся

можно ли задать дополнительный ряд операций над получаемыми данными? то есть указать, что к примеру %1\$d равно $row['numb']*10/5, или просуммировать два других значения


единственное, что придумывается - это указать аргументом имя другой функции /пользовательской/, в которую будут подставляться данные

а нет ли более простого хода?

Это сообщение отредактировал(а) bars80080 - 27.8.2009, 17:30
PM MAIL WWW   Вверх
IZ@TOP
Дата 27.8.2009, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Панда-бир!
****


Профиль
Группа: Участник
Сообщений: 4795
Регистрация: 3.2.2003
Где: Бамбуковый лес

Репутация: 44
Всего: 73



bars80080, я, если честно, не особо понял, что именно требуется от sprintf'а, но если он что-то не умеет (а что умеет, я думаю, сам знаешь где посмотреть), то я бы на твоем месте написал под свою задачу собственный парсер/логику. Если, разумеется, это не противоречит условиям задачи.


--------------------
Один из розовых плюшевых-всадников апокалипсиса... очень злой...

Семь кругов ада для новых элементов языка
Мои разрозненные мысли
PM MAIL WWW ICQ Skype GTalk   Вверх
bars80080
Дата 27.8.2009, 18:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



парсер... может быть, но комбинации могут быть достаточно сложны. 

к примеру, вывести первые 30 символов от строки данных

писать парсер, который будет воспринимать пхп-шные функции, наверно слишком объёмно

видимо, придётся кидать ссылку на пользовательскую функцию, в которой можно будет прописать необходимые действия и вернуть результат
PM MAIL WWW   Вверх
NewDima
Дата 27.8.2009, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 922
Регистрация: 20.2.2006
Где: <?here?>

Репутация: 10
Всего: 12



что то тут вроде...
Код

<?php
    function insertValues($str, $values) {
        $pattern = '#%(\d+)\$([sd]{1,1})#';
        $func = create_function("\$mt",
            "\$array=".var_export($values, true).";
             if (isset(\$array[(int)\$mt[1]-1])) return \$array[(int)\$mt[1]-1];
             throw new exception('invalid pointer value =))');");
        return preg_replace_callback($pattern, $func, $str);
    }

    echo insertValues("The %2\$s contains %1\$d monkeys. That's a nice %2\$s full of %1\$d monkeys.", array('numb', 'location'));
?>


Добавлено @ 18:15
или не оно? лямбда подойдет?

Это сообщение отредактировал(а) NewDima - 27.8.2009, 18:21
PM ICQ   Вверх
IZ@TOP
Дата 27.8.2009, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Панда-бир!
****


Профиль
Группа: Участник
Сообщений: 4795
Регистрация: 3.2.2003
Где: Бамбуковый лес

Репутация: 44
Всего: 73



bars80080, прости, туплю, видимо вечер сказывается. Тебе свой микроскриптовый язык нужен?


--------------------
Один из розовых плюшевых-всадников апокалипсиса... очень злой...

Семь кругов ада для новых элементов языка
Мои разрозненные мысли
PM MAIL WWW ICQ Skype GTalk   Вверх
Ипатьев
Дата 27.8.2009, 19:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



скорее, парсер printf формата
я так понимаю, что его бы устроила функция, котора я "повыкусывала" бы из строки все printf-последовательности, и вернула их вместе с позициями.
я думаю, такую вполне можно написать, как регом, так и перебором. главное, хорошую доку по форматам найти.
возможно, кстати, в сети и есть уже готовый рег.
PM MAIL   Вверх
NewDima
Дата 27.8.2009, 19:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 922
Регистрация: 20.2.2006
Где: <?here?>

Репутация: 10
Всего: 12



Я видать неправильно понял задачу? Аргумент-массив - это типа домены таблицы базы данных, значение которых нужно узнать?
PM ICQ   Вверх
Ипатьев
Дата 27.8.2009, 19:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



нет, это похоже, я не до конца дочитал
похоже, да - скриптовый язык будет самое правильное определение. вот только не микро-, если там уже есть арифметика и строковые функции.
осталось понять нафига козе такой тяжелый и неудобный баян...
я бы порекомендовал смарти - там все заявленное уже есть.
PM MAIL   Вверх
bars80080
Дата 28.8.2009, 00:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



Цитата(Ипатьев @  27.8.2009,  19:18 Найти цитируемый пост)
похоже, да - скриптовый язык будет самое правильное определение. вот только не микро-, если там уже есть арифметика и строковые функции.

что-то да


Цитата(Ипатьев @  27.8.2009,  19:18 Найти цитируемый пост)
осталось понять нафига козе такой тяжелый и неудобный баян...
я бы порекомендовал смарти - там все заявленное уже есть. 

а при чём здесь смарти? и при чём вообще шаблонизатор? собирать ведь можно что-угодно




Цитата(IZ@TOP @  27.8.2009,  18:19 Найти цитируемый пост)
Тебе свой микроскриптовый язык нужен? 

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

если решения нет, то понятное дело придётся писать самому


NewDima, я думаю можно проще, без генерации внутренней функции, а просто указанием имени внешней

Это сообщение отредактировал(а) bars80080 - 28.8.2009, 00:06
PM MAIL WWW   Вверх
icewind
Дата 28.8.2009, 00:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 393
Регистрация: 11.4.2009
Где: Ростов-на-Дону

Репутация: 20
Всего: 20



Цитата(bars80080 @  28.8.2009,  00:02 Найти цитируемый пост)
хех знает, может быть есть и какие-то внутренние механизмы вычисления (кто там знает, сколько всякие библиотек и прочего написано)

Не думаю...

Возможно функция create_function поможет в создании такого инструмента


--------------------
user posted image
PM MAIL Skype   Вверх
NewDima
Дата 28.8.2009, 04:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 922
Регистрация: 20.2.2006
Где: <?here?>

Репутация: 10
Всего: 12



Цитата

Возможно функция create_function поможет в создании такого инструмента 

icewind, когда что-то пишешь, смотри все сообщения =)
Цитата

NewDima, я думаю можно проще, без генерации внутренней функции, а просто указанием имени внешней

легко, но ты хотел без дополнительной функции smile переделать то две минуты

PM ICQ   Вверх
Ипатьев
Дата 28.8.2009, 07:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



Совершенно верно. Шаблонизатором можно собирать что угодно. smile
Цитата(bars80080 @  28.8.2009,  00:02 Найти цитируемый пост)
мне не нужно, я спрашиваю о решении. 

 smile 

PM MAIL   Вверх
NewDima
Дата 28.8.2009, 09:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 922
Регистрация: 20.2.2006
Где: <?here?>

Репутация: 10
Всего: 12



Уф, ну все, накатал. Только не пинайте))
В общем я тут подумал, пописал. И вот что накатал:
Три класса (наследование): парсер->функционал->внешние данные
В парсере определил сам метод разбиения строки, метод вызова вычисления, который в свою очередь вызывает пользовательские методы из класса "функционал". Класс функционал реализует несколько необязательных функций, которые работают над данными (сложение чисел, умножение, возведение в квадрат, в общем что дуща пожелает). Последний класс, который работает с внешними данными (собственно как bars80080 говорил про данные, которые вытаскиваются из базы) и представляет их абстракному классу предку парсеру.
У парсера два публичных метода:
public function parseValues($str, $values)
принимает строку форматирования и значения в массиве $values. Значения имею специфический  формат, но простой, я пытался проще придумать. Формат значения:
1. если строка, то подразумевается, что эта строка может являеться глобальным ключом, к которому можно обращаться из любого места массива, потом покажу как. В противном случае, по абстрактному методу определяется, есть ли по данному ключу чтонибудь в данных (например из базы), елси есть, то вставляется оттуда. Если нигде не определено значение ключа, то значением является сам ключ.
2. если массив, то в массиве должен быть определен ключ '#opcode#', значение которого - операция, которую нужно совершить над остальными элеменати массива и вернуть. Если опкод не определен, то выбрасывается исключение.
3. если любой другой тип, то он возвращается сам.
public function toggleDebug()
включает или выключает дебаг (там видно сразу, как работает парсер), по умолчанию дебаг отключен.
Имя класса - stringParser, абстрактный.

Класс функционала не имеет публичных функций, реализует защищенные функции, имя которых начинается с двух прочерков, а далее идет опкод команды (тот самый, который определен в массивах).
Имя класса - extendedParser, абстрактный.

Класс данных собственно предназначен для того, чтобы брать данные из определенныйх мест, например из базы данных.
Обязан реализовать две защищенные функции:
_isInternalKey($key)
По ключу определяет, имеются ли данные для этого ключа
_internalKeyValue($key)
Возвращает ассоциированные с ключом данные.

Опишу "функции"  smile  в массиве
записывается примерно так:
Код

array('#opcode#' => 'summ', //может быть любой опкод, для которого есть действие в классе extendedParser
  1,
  2
  3 ... любое количество элементов
)

Функции поддерживают вложенность:
Код

array('#opcode#' => 'summ', //может быть любой опкод, для которого есть действие в классе extendedParser
  1,
  array('#opcode#' => 'mult',
    13,
    14.5
    array('#opcode#' => 'neg',
      143,
       441
    ),
  ),  
)


Приведу код класса stringParser
Код

abstract class stringParser {
    protected $indexed = array();
    protected $values = array();
    protected $pointers = array();
    protected $startTime;
    protected $debug = false;

    protected abstract function _internalKeyValue($key);
    protected abstract function _isInternalKey($key);

    protected function debug($str) {
        if (!$this->debug) return;
        echo $str."\n";
    }
    protected function isIndexed($key) {
        return isset($this->indexed[$key]);
    }
    protected function getIndexed($key) {
        return $this->indexed[$key];
    }
    protected function setIndexed($key, $value, $level) {
        if ($level !== 0) return;
        $this->debug('setting index ['.$key.', '.var_export($value, true)."]");
        return $this->indexed[$key] = $value;
    }

    protected function resultValues($params) {
        $arr = array();
        foreach ($params as $key => $value) {
            $arr[] = $this->_calcValue($key, $value);
        }
        return $arr;
    }

    protected function _calcValue($key, $value, $level = -1) {
        $this->debug("calcing value [$key, $value]");
        if (mktime() !== $this->startTime) throw new exception ('execution time is too long ('.(mktime()-$this->startTime).')');
        if (is_string($key) && $this->isIndexed($key)) {
            $this->debug("result was indexed by key; returning");
            return $this->getIndexed($key);
        } elseif (is_numeric($key) && is_string($value) && $this->isIndexed($value)) {
            $this->debug("result was indexed by value; returning");
            return $this->getIndexed($value);
        }
        switch (true) {
            //value - string
            case is_string($value): {
                if (isset($this->values[$value])) {
                    $result = $this->_calcValue($value, $this->values[$value], 0);
                } else {
                    if ($this->_isInternalKey($value)) {
                        $result = $this->_fromDb($value);
                    } else {
                        $result = $value;
                    }
                }
                break;
            }
            //value - array
            case is_array($value): {
                if (isset($value['#opcode#'])) {
                    $opcode = '__'.$value['#opcode#'];
                    if (!method_exists($this, $opcode)) {
                        throw new exception ("An unsupported operation was requested,\n that have not been implemented yet. [opcode=$opcode]");
                    }
                    unset($value['#opcode#']);
                } else {
                    throw new exception ("There is no operation code for operands.\n No operation code for default use");
                }
                $operands = array();
                foreach ($value as $newkey => $newvalue) {
                    $operands[] = $this->_calcValue($newkey, $newvalue);
                }
                $result = call_user_method($opcode, $this, $operands);
                break;
            }
            //value - another type
            default: { //for other types, including integer and etc.
                $result = $value;
            }
        }
        if (is_string($key) && ($level === 0)) {
            $this->setIndexed($key, $result, $level);
        } elseif (is_numeric($key) && is_string($value) && ($level === 0)) {
            $this->setIndexed($value, $result, $level);
        }
        $this->debug("calcling result is $result");
        return $result;
    }

    protected function _getValue($match) {
        $key = (int)$match[1]-1;
        if (isset($this->pointers[$key])) { echo $this->values[$key];
            return $this->indexed[ $this->pointers[$key] ];
        }
        $this->debug("no argument was found for key '$key'\n");
    }

    public function parseValues($str, $values) {
        $this->startTime = mktime();
        $this->values = $values;
        $this->pointers = array();
        foreach ($values as $key => $value) {
            $this->setIndexed($key, $this->_calcValue($key, $value, 0), 0);
            if (is_string($key)) {
                $this->pointers[] = $key;
            } elseif (is_string($value)) {
                $this->pointers[] = $value;
            } else {
                $this->pointers[] = NULL;
            }
        }
        $pattern = '#%(\d+)\$([sd]{1,1})#';
        return preg_replace_callback($pattern, array($this, '_getValue'), $str);
    }
    public function toggleDebug() {
        $this->debug = !$this->debug;
    }
}

Класс extendedParser (его можно реализовать так, как надо, добавлять нужные функции, убирать ненужные, очень легко)
Код

abstract class extendedParser extends stringParser {

    protected function __summ($params) { // a+b+c+...
        return array_sum($this->resultValues($params));
    }

    protected function __neg($params) { // -(a+b+c+...)
        return -$this->__summ($params);
    }

    protected function __minus($params) {// a-b-v-c-...
        $params = $this->resultValues($params);
        if (!count($params)) return 0;
        $first = $params[0];
        unset($params[0]);
        return $first - array_sum($params);
    }

    protected function __mult($params) { // a*b*c*d*...
        $result = 1;
        foreach ($params as $key => $value) {
            $result *= $this->_calcValue($key, $value);
        }
        return $result;
    }

    protected function __concat($params) {// a.b.c.d.*
        return implode('', $this->resultValues($params));
    }

    protected function __pow2summ($params) {// a^2+b^2+c^2+...
        $arr = array();
        foreach ($params as $key => $value) {
            $val = $this->_calcValue($key, $value);
            $val *= $val;
            $arr[] = $val;
        }
        return array_sum($arr);
    }
    protected function __sqrtsumm($params) {// sqrt(a) + sqrt(b) + sqrt(c) + ...
        $arr = array();
        foreach ($params as $key => $value) {
            $val = $this->_calcValue($key, $value);
            $val = sqrt($val);
            $arr[] = $val;
        }
        return array_sum($arr);
    }
}

Класс dbXParse (он у меня практически пустой, н там все ясно)
Код

class dbXParse extends extendedParser {
    protected $dbResult = array();
    protected function _isInternalKey($key) {
        return isset($this->dbResult[$key]);
    }

    protected function _internalKeyValue($key) {
        return $this->dbResult[$col];
    }
}

для примера я составил парсинг вот таких функций:
Код

  totalLength10 = (topicLength + headerLength) * 10
  concatResult = '#'.1.2.'345'.6.7.'#'
  y = x^2 + k
  s = sqrt(p*(p-a)*(p-b)*(p-c))
  p = (a+b+c)/2

Пример массива для этих всех функций со всеми параметрами
Код

$params = array(
  'totalLength10' => array('#opcode#' => 'mult', //totalLength10 = (topicLength + headerLength) * 10
      array ('#opcode#' => 'summ',
        'topicLength','headerLength' //те самые, которые используются в корне массива
      ),
      10
  ),
  'topicLength'=>1,
  'headerLength'=>2,
  'concatResult' => array('#opcode#' => 'concat', //concatResult = '#'.1.2.'345'.6.7.'#'
      '#', 1, 2, '345', 6, 7, '#'
  ),
  'y' => array('#opcode#' => 'summ',  //y = x^2 + k
    array('#opcode#'=>'pow2summ', 'x'),
    'k'
  ),
  'x' => 2,

  'a' => 2,
  'b' => 2,
  'c' => 3,
  's' => array('#opcode#'=>'sqrtsumm',  //s = sqrt(p*(p-a)*(p-b)*(p-c))
    array('#opcode#'=>'mult',
      'p',
      array('#opcode#' => 'minus', 'p','a'),
      array('#opcode#' => 'minus', 'p','b'),
      array('#opcode#' => 'minus', 'p','c')
    )
  ),
  'p' => array('#opcode#' => 'mult',//p = (a+b+c)/2
    array('#opcode#' => 'summ',
      'a', 'b', 'c'
    ),
    1/2
  )
);

Шаблон для вывода думаю вставлять не стоит, и так много текста, но он такого же формата, как и у bars80080
Использование:
Код

$parser = new dbXParse();
echo $parser->parseValues($outputer, $params);

вывод:
Код

 totalLength10 = (topicLength + headerLength) * 10     30 = (1 + 2) * 10
concatResult = '#'.1.2.'345'.6.7.'#'     concatResult = #1234567#
y = x^2 + k    4 = 2
s = sqrt(p*(p-a)*(p-b)*(p-c))     1.9843134833 = sqrt(3.5*(3.5-2)*(3.5-2)*(3.5-3))
p = (a+b+c)/2    3.5 = (2 + 2 + 3) / 2

Вот такой вот прикол smile

Добавлено через 6 минут и 48 секунд
ой, там 4=2 =) это я в шаблоне ошибся)

Добавлено через 13 минут и 32 секунды
Тут исходник, на всякий случай))

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  buka.rar 4,32 Kb
PM ICQ   Вверх
bars80080
Дата 28.8.2009, 11:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



спасибо, будем ковырять
PM MAIL WWW   Вверх
NewDima
Дата 28.8.2009, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 922
Регистрация: 20.2.2006
Где: <?here?>

Репутация: 10
Всего: 12



главное, чтобы в помощь)
PM ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0654 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.