жадность preg_replace

Kachalov

Новичок
Всем доброго времени суток!
Возникла проблема. Имеется такой код:
PHP:
if(preg_match('/{if (.*?)}(.*?){\/if}/isU', $this->content))
		{
			$if = preg_replace('/(.*?){if (.*?)}(.*?){\/if}(.*?)/is', '$2', $this->content);
			if(!empty($if))
			{
				$true = false;
				eval("if($if)\$true = true;");
				echo "if($if)\$true = true;\r\n";
				
				if($true)
				$this->content = preg_replace('/(.*?){if (.*?)}(.*?){\/if}(.*?)/is', '$3', $this->content);
				else
				$this->content = preg_replace('/(.*?){if (.*?)}(.*?){\/if}(.*?)/is', '', $this->content);
			}
		}
и $this->content равный:
PHP:
{if !$loggedin}
Не авторизирован
{/if}
{if $loggedin}
Авторизирован
{/if}
Собственно проблема в том, что $if='!$loggedin$loggedin'; Может быть кто-нибудь подскажет как исправить или в какую сторону копать?
 

wolfram

Новичок
'/(.*?){if (.*?)}(.*?){\/if}(.*?)/isU'

В preg_match модификатор U указан, а в preg_replace забыли.
 

Kachalov

Новичок
Костыль такой:
PHP:
if(preg_match('/{if (.*?)}(.*?){\/if}/isU', $this->content))
		{
			$if = preg_replace('/{if (.*?)}(.*?){\/if}/is', '$1', $this->content);
			foreach(explode("\r\n",$if) as $if)
			if(!empty($if))
			{
				$true = false;
				eval("if($if)\$true = true;");
				//echo "if($if)\$true = true;\r\n";
				
				$if = str_replace(
				array('/','$','[',']','{','}'),
				array('\/','\$','\[','\]','\{','\}'),$if);
				
				if($true)
				$this->content = preg_replace('/{if '.$if.'}(.*?){\/if}/is', '$1', $this->content);
				else
				$this->content = preg_replace('/{if '.$if.'}(.*?){\/if}/is', '', $this->content);
			}
		}
Но при этом невозможно делать вложение if в if. Да и что-то мне подсказывает, что такой костыль на производительности скажется.
 

Тугай

Новичок
Уже было недавно,
(.*?)} - в такой ситуации когда нужен любой символ до скобки а потом скобка, надо писать ([^}]*)} - т.е. не скобка потом скобка.
PHP:
preg_match('/{if ([^}]*)}([^{]*){\/if}/isU', $this->content)
Ну и в /isU - U - жадность переворачивает и .*? -- получается жадным, если писать .*? , то тогда без U.
 

Kachalov

Новичок
Условия, разделённые \r\n. Хотя всё это, как один большой костыль, который мне потом, видимо, воткнётся в одно место. Мда. Натыкался на такую же проблему при парсинге BB-code. Может быть можете подстазать, где почитать о таких регулярках?
 

Вурдалак

Продвинутый новичок
Регулярки если в подобных случаях и используют, то только для токенизации (лексера). Гуглить на тему лексического и синтаксического анализа, посмотреть реализацию xbb, Twig, например.
 

Kachalov

Новичок
Тебе это для учебы или для дела?
Если для дела, то это делается так:
PHP:
$smarty = new Smarty();
$smarty->assign('loggedin', $loggedin);
$this->content = $smarty->fetch('string:'.$this->content);
Все еще есть желание изобретать велосипеды?
Пользовался Smarty, но он слишком громоздкий, плюс к этому регулярки подучить, так как с ними, как видите, у меня большие проблемы.

П.С.: у меня страница со Смарти, которая тянет 3 запроса к БД загружается 75мс. Для сравнения то, над чем сейчас работаю я, грузится за 37мс обращаясь к API, который тянет намного больше запросов, а потом ещё и шаблоны натягивает.
 

keltanas

marty cats
Но, ты даже не понимаешь, что хочешь получить в результате работы своего кода.
preg_replace за тебя не будет выполнять логику.
 

Kachalov

Новичок
Но, ты даже не понимаешь, что хочешь получить в результате работы своего кода.
preg_replace за тебя не будет выполнять логику.
При этом код заработал, правда не получилось делать подусловия. Я же сказал: "Это - костыль". Что делает pre_replace я понимаю, хотя, местами не до конца.
 

Kachalov

Новичок
Он реплэйсит. Что тут не понятного?

Так я привел уже пример не-костыля, а тебе не нравится.
Я то это прекрасно понимаю, что он оставляет только условия, а остальное убирает. Получается набор условий, каждое с новой строки, которые мы превращаем в массив и снова идём вырезать ненужное, но уже "с умом". Но приходится 2 раза реплейсить одно и то же, плюс к этому невозможно добавлять подусловия. Поэтому костыль. А насчёт того, что Вы предложили, я ответил: "Smarty слишком тяжёловесный и медленный для моей цели".
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
П.С.: у меня страница со Смарти, которая тянет 3 запроса к БД загружается 75мс. Для сравнения то, над чем сейчас работаю я, грузится за 37мс обращаясь к API, который тянет намного больше запросов, а потом ещё и шаблоны натягивает.
О, сразу классический анекдот вспомнился:
Секретаршу принимают на работу:
- У вас в резюме написано, что вы печатаете со скоростью 1000 знаков в минуту. Это правда?
- Правда! Но такая ерунда получается...
 

keltanas

marty cats
Ну, если думаешь, что умнее дядек, которые уже несколько лет пишут Smarty, то может пропробовать реплэйсить условия в PHP-код, а уже этот код евалить?
PHP:
<?php
$content = '{if !$loggedin}
Не авторизирован
{/if}
{if $loggedin}
Авторизирован
{/if}';

$re = '/(?:{if(.*?)}\s(.*?)\s{\/if})/';

$code = preg_replace($re, 'if($1){return\'$2\';}', $content);

$loggedin = false;
print eval($code) . PHP_EOL;
 

Kachalov

Новичок
Ну, если думаешь, что умнее дядек, которые уже несколько лет пишут Smarty, то может пропробовать реплэйсить условия в PHP-код, а уже этот код евалить?
PHP:
<?php
$content = '{if !$loggedin}
Не авторизирован
{/if}
{if $loggedin}
Авторизирован
{/if}';

$re = '/(?:{if(.*?)}\s(.*?)\s{\/if})/';

$code = preg_replace($re, 'if($1){return\'$2\';}', $content);

$loggedin = false;
print eval($code) . PHP_EOL;
Я не думаю, что я умнее. Просто мне хочется написать свой шаблонизатор. Да, изобретать велосипед полезно бывает разве что для саморазвития. Да, смарти работает быстро, но, если страницы кешировать. Такие шаблонизаторы, как Смарти и Твиг проверены временем и комьюнити, но мне не нужно столько функционала. Мне всего-то нужно натянуть "шкурку" да переменные туда пихнуть. В принципе можно было обойтись и без условий, но тогда будет слишком много лишних шаблонов.
 

keltanas

marty cats
Можно еще такой костыль, в принципе.
PHP:
<?php
$content = 'Привет
{if !$loggedin}
Не авторизирован
{/if}
{if $loggedin}
Авторизирован
{/if}
мир!';

$re = '/\s?(?:{if(.*?)}\s(.*?)\s{\/if})/';

$loggedin = true;

var_dump( preg_replace_callback($re, function($match) use($loggedin) {
    return eval("return {$match[1]}?'{$match[2]}':'';");
}, $content) );
Но учти, что все условия будут евалится, как есть. Т.о. в этот шаблон можно будет инъектировать что-то интересное ;)
 
Сверху