Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Регулярные выражения и условные конструкции

21K
13 июля 2009 года
evil_rabbit
60 / / 27.08.2008
Доброго времени суток, товарищи. Не подскажете ли Вы мне как сформулировать регулярное выражение для проверку конструкции подобного вида:
 
Код:
[if(val1=val2)]
 sometext
[endif]

и/или:

 
Код:
[for(1;2)]
 sometext
[endfor]

где (1;2) значит: начинать со значения 1 и делать 2 раза (это так для справки).
Мои безуспешные попытки написать нечто вроде: "/\{if\((.*?)(<=>)(.*?)\)\}\{\endif}/is", ничего не дали. Использую preg_replace_callback($regexp, "if_func", $str);
И не понимаю, что передается в if_func - массив значений или просто несколько значений. Не гуглится как-то ничего путного/похожего.
Заранее благодарен.
312
13 июля 2009 года
dead_star
392 / / 26.11.2006
ну для начала хочется сказать что в таких делах лучше использовать шаблонизатор Smarty
во вторых в примерах у тебя элименты закрыты в квадратных скобках[], а в регулярке ты выбираешь фигурные{}
от чегу у тебя ничего и не получается
и при выборе неравенства ты ищешь <=> , а тбе надо одно из трех
соответственно регулярка должна бриобрести подобный вид
 
Код:
/\[if\((.*)([<=>]{1})(.*)\)\](.*)\[endif\]/is

и в функции ты получаешь
Код:
Array
(
    [0] => [if(val1=val2)]
 sometext
[endif]
    [1] => val1
    [2] => =
    [3] => val2
    [4] =>
 sometext

)
21K
13 июля 2009 года
evil_rabbit
60 / / 27.08.2008
dead_star, спасибо Вам за старания, но я после 4 часов раздумий, проб, ошибок и ритуального стучания головой об клавиатуру, решил сею проблему. Прилагаю исходник, может он кому-нибудь понадобится, ибо когда я гуглил, то ничего путного не нашел.

Код:
function cond_if($cond=array())
 {$res='';
  //cond[1] - первое значение
  //cond[2] - символ сравнения, больше, меньше и т.д.
  //cond[3] - второе значение
  //cond[4] - содержание
  switch($cond[2])
  {
   case '=':{if($cond[1]==$cond[3])$res=$cond[4]; break;}
   case '<': {if($cond[1]<$cond[3])$res=$cond[4]; break;}
   case '>': {if($cond[1]>$cond[3])$res=$cond[4]; break;}
   case '<=': {if($cond[1]<=$cond[3])$res=$cond[4]; break;}
   case '>=': {if($cond[1]>=$cond[3])$res=$cond[4]; break;}
   case '<>': {if($cond[1]<>$cond[3])$res=$cond[4]; break;}
  }
  return($res);
 }

$str=file_get_contents('template.html'); //получаем шаблон

$str=preg_replace_callback('/\[if\((.*?)([<=>]{1,2})(.*?)\)\](.*?)\[endif\]/is',    'cond_if',$str); //выполняем преобразование
echo $str; //выводим результат


Теперь буду делать цикл. Результат своих изысканий выложу в этой теме.

P.S. так и думал что Вы предложите Smarty ;)
5
13 июля 2009 года
hardcase
4.5K / / 09.08.2005
Такие конструкции принципиально не по силам классическим регулярным выражениям. (в Perl можно, правда придется разрушить левое полушарие мозга).

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

Для решения задачи вам потребуется написать собственный парсер или описать грамматику и его вам сгенерирует какой-нибудь инструмент типа bison или coco/r.

В ручную написать не так сложно. Идея тут примерно такая же как и в случае с интерпретатором арифметических выражений. Только для поиска управляющих конструкций в вашем случае вполне можно использовать регулярные выражения. В итоге получится рекурсивный нисходящий парсер.


З.Ы. Могу накидать такой парсер на C#. При условии описания с вашей стороны языковых кострукций. С виду язык напоминает юниксовый макропроцессор m4.
21K
13 июля 2009 года
evil_rabbit
60 / / 27.08.2008
hardcase, да мне много и не надо. Но я конечно планировал нечто подобное, но как реализовать не знал. Спасибо Вам за ссылки. Буду развивать.
А пока представляю цикл for:

Код:
function cond_for($cond)
 {$res=''; //результирующая строка, изначально пустая
   $j=$cond[1]; //начальное значение
  while($j<=$cond[2])
  {
   $j++;
   $res=$res.$cond[3]; //добавляем результат
  }
  return($res); //возвращаем результат
 }

$str=file_get_contents('template.html'); //получаем шаблон

$str=preg_replace_callback('/\[for\(([0-9]{1,5});([0-9]{1,5})\)\](.*?)\[endfor\]/is', 'cond_for',$str);


-----UPD
А как можно получить значение переменной по имени, таким образом не получилось:
 
Код:
$somestr='var1';
echo $$somestr;
21K
13 июля 2009 года
evil_rabbit
60 / / 27.08.2008
Цитата: hardcase

З.Ы. Могу накидать такой парсер на C#. При условии описания с вашей стороны языковых кострукций. С виду язык напоминает юниксовый макропроцессор m4.



Если Вам не трудно, и Вы не боитесь того, что это станет всем доступно, то пожалуйста выкладывайте в тему, буду благодарен.
Конструкции языка довольно простые:
if-endif:

 
Код:
[if(val1=val2)] //где val1 и val2 могут быть либо числом, либо текстом, и перед
//круглыми скобками не должно быть пробелов (собственно как и после)
text
[endif]


for:
 
Код:
[for(start;count)] //start - начальное значение, count - кол-во повторений
text
[endfor]


$somevar - подстановка переменной

Разумеется все это будет еще дорабатываться, и в конце концов, будет отдано на всеобщее обозрение.
16K
13 июля 2009 года
k0t
97 / / 23.04.2007
Цитата:
-----UPD
А как можно получить значение переменной по имени, таким образом не получилось:
 
Код:
$somestr='var1';
echo $$somestr;



Можете попробовать так ${$somestr}

312
13 июля 2009 года
dead_star
392 / / 26.11.2006
Цитата: evil_rabbit

-----UPD
А как можно получить значение переменной по имени, таким образом не получилось:
 
Код:
$somestr='var1';
echo $$somestr;


думаю что проблема в уровне объявления переменных
подозреваю что ты хотел сделать что-то на подобии этого

 
Код:
$var = "test";
function func($var_name){
 global $$var_name;
 echo $$var_name;
}
func("var");
5
13 июля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: evil_rabbit
Конструкции языка довольно простые:
if-endif:
 
Код:
[if(val1=val2)] //где val1 и val2 могут быть либо числом, либо текстом, и перед
//круглыми скобками не должно быть пробелов (собственно как и после)
text
[endif]


Хмм [else] всетаки необходим.
Не ясно в какой момент вычисляется val1 и val2. Откуда они берутся?

21K
13 июля 2009 года
evil_rabbit
60 / / 27.08.2008
k0t, благодарю, способ работает.

dead_star, я не совсем понял Вас. Мне нужно просто по имени переменной к ней (переменной) обратиться.
Цитата: hardcase
Хмм [else] всетаки необходим.
Не ясно в какой момент вычисляется val1 и val2. Откуда они берутся?



else подразумевалось в перспективе, а здесь был просто упрощенный вид. Как я понимаю [else] ставить между [if...] и [endif]?
val1 и val2 - это переменные, которые подставляются на раннем этапе разбора шаблона. Также могут быть просто, заранее объявленными значениями либо константами.
Я так раскинул мозгом и придумал "рекурсивный" метод. Объясняю:
функцией preg_match_all с флагом PREG_OFFSET_CAPTURE, получаем все вхождения со смещениями для if, else и endif. Если, допустим, стоят 2 или более if'а подряд, то некий счетчик $rec_lvl увеличиваем, а когда встречаем endif, то уменьшаем.
Изначально придумывалось без [else], а с ним, наверное так: каждому [else] присваивать индекс = $rec_lvl, и на его основании делать выводы.

Знаете кого-то, кто может ответить? Поделитесь с ним ссылкой.

Ваш ответ

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог