Регулярные выражения, уменьшение жадности

Invizz

Новичок
Регулярные выражения, уменьшение жадности

Опять я. Вопрос, который не могу разрешить уже много времени:

есть строчка

This is a 'test str\'ing' and 'quotes here are \' just for test'

Чтобы отловить фразы в неэкранированых кавычках я использую выражение

((?<!\\)('|")(.*?)(?<!\\)\2):

'test str\'ing'
'quotes here are\' just for test'

А как отловить только фразы в кавычках, внутри которых обязательно встречается слово here? Если сделать

((?<!\\)('|")(.*?)(here)(.*?)(?<!\\)\2):

то выражение становится очень жадным и выдаст
' and 'quotes here are \' just for test'

Как исправить его жадность?

На манюалы не отправлять, перечитал все что можно.
 

Invizz

Новичок
По-моему в данном случае панацея.
Теперь моя идея такова:

Заменить все специальные (INSERT, INTO,ORDER,LIMIT и т д)слова в отловленных фразах на ~~~слово~~~.

Таким образом не будет использовано левых переменных, массивов, результаты не будут запоминаться. Довольно быстро выполняться будет.

А после преобразований через str_replace, который самый быстрый среди реплейсов, просто-напросто пропустить массив array('~~~SELECT~~~'=>'SELECT,'~~~INSERT~~~',..) натравленный на измененный запрос.

Лучше всего вместо ~~~ использовать какие-нибудь кавычки, потому что потенциальный инжектор не сможет неэкранированные кавычки вставить в запрос. А реплейс сможет.
 

white phoenix

Новичок
По теме именно рег. выражений: условные подмаски тут явно не нужны:
PHP:
$string = "Simple text 'quoted text' \'quoted with backslashes\' 'testing' ...";
$result = preg_match_all('~[^\\\]\'(.*[^\\\])\'~U',$string,$matches);
var_dump($result,$matches);
/*
int(2)
array(2) {
  [0]=>
  array(2) {
    [0]=>
    string(14) " 'quoted text'"
    [1]=>
    string(10) " 'testing'"
  }
  [1]=>
  array(2) {
    [0]=>
    string(11) "quoted text"
    [1]=>
    string(7) "testing"
  }
}
*/
UPD: но это не панацея действительно
 

SiMM

Новичок
white phoenix
PHP:
$string = "Simple text 'quoted text\\\\' \'quoted with backslashes\' 'testing' ...";
> Заменить все специальные (INSERT, INTO,ORDER,LIMIT и т д)слова в отловленных фразах на ~~~слово~~~.
Это то же самое, что к инвалидной коляске добавить костыли - само по себе это больного не излечит.
 

white phoenix

Новичок
SiMM
И что?
Simple text 'quoted text\' \'quoted with backslashes\' 'testing' ...
Первая неэкранированная ковычка означает начало строки, а вторую (перед "testing") принимаем за её конец.
Находит:
string(42) "quoted text\' \'quoted with backslashes\' "
Т.к. остается {testing'} без второй ковычки.
 

Invizz

Новичок
white phoenix
Да, этот вариант, действительно, лучше. Но по теме... Это возможно и не панацея, но это лучше того, что наворотили другие девелоперы (отнюдь не дураки).

Вообщем, как быть в условиях данной задачи? Как просчитать наличие некоего слова внутри, причем с наименьшей жадностью? Можно покопать в сторону посикс... Но может у гуру будут советы получше?

Всем спасибо в любом случае.
 

SiMM

Новичок
> И что?
Пост исправил.
Simple text 'quoted text\\' \'quoted with backslashes\' 'testing' ...
> будут советы
Я вам уже дал один совет. Но судя по тому, что вы его проигнорировали - вам нужно готовое решение. Я их не даю. Принципиально.
 

white phoenix

Новичок
SiMM
> Пост исправил.
А в чем разница?
> Я их не даю. Принципиально.
А почему? :)
 

Invizz

Новичок
SiMM
Если вы говорите о том коде на руборде. Да это быстрее для той задачи. Теперь она изменилась. Или даже не наметилась. Идеология моей задачи спорна крайне, но и я уже не знаю, правильной дорогой ли я пошел. Советы я имел в виду идеологические в этом направлении. Не панацея - так что же панацея? Вопрос риторичен, я не прошу сейчас никаких готовых решений - чай не дурак и разобраться, думаю, смогу. Вопрос в рамках этого топика обозначен в первом посте.

Ноу оффенс.
 

SiMM

Новичок
white phoenix, почитайте для начала, откуда у него эта задача выползла. Те костыли, которые он пытается поставить - выползают оттуда. Именно поэтому у вас должно получаться
Код:
    [0] => Array
        (
            [0] =>  'quoted text\\'
            [1] =>  'testing'
        )

    [1] => Array
        (
            [0] => quoted text\\
            [1] => testing
        )
а не
Код:
    [0] => Array
        (
            [0] =>  'quoted text\\' \'quoted with backslashes\' '
        )

    [1] => Array
        (
            [0] => quoted text\\' \'quoted with backslashes\' 
        )
> А почему?
Потому что наивно полагаю, что дойти своим умом куда приятнее и полезнее, чем сделать Copy&Paste не задумываясь.

> Вопрос в рамках этого топика обозначен в первом посте.
Вопрос в рамках этого топика не сам по себе возник. Рассматривать надо исходную задачу, а не участок, до которого вы дошли в результате своих попыток решения.

В любом случае - я своё мнение сказал. В конечном итоге - всё равно решать вам. Мне же кажется что всё гораздо проще.
 

Invizz

Новичок
Может и проще, объясню свою логику, с вашего позволения:

Раз отпадает возможность изменить все запросы во всем движке - нужно делать это в одном месте и сразу. Для всех.

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

Поиск производится по ключевым слова таким как SELECT, ORDER & другие.

Там неплохая логика, проверка типа запроса и все такое.

Но если в запросе появляются пользовательские специальные слова... То все крешится, запрос превращается в кашу.

Как избавиться? Экранировать.

Сначала решил выдирать и вставлять потом - медленно.

Тепеь просто экранировать символами.

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

Вот и ломаю голову.
 

white phoenix

Новичок
SiMM
Получите, распишитесь :)
PHP:
$string = " 	Simple text 'quoted text\\\' \'quoted with backslashes\' 'testing' ...  ";
$pattern = '~[^\\\]{1,2}\'(.*[^\\\]{0,2})\'~U';
$result = preg_match_all($pattern,$string,$matches,PREG_SET_ORDER);
var_dump($result,$matches);
/*
int(2)
array(2) {
  [0]=>
  array(2) {
    [0]=>
    string(17) "t 'quoted text\\'"
    [1]=>
    string(13) "quoted text\\"
  }
  [1]=>
  array(2) {
    [0]=>
    string(11) "' 'testing'"
    [1]=>
    string(7) "testing"
  }
}
*/
 

Invizz

Новичок
Сделал, наконец-таки.

Сделал с помощью алгоритма SIMM:

PHP:
$replacement=array("blog_id","INSERT","SELECT","JOIN","VALUES","LIMIT","GROUP","ORDER","WHERE");
$newq= $query;
				
$f = false; 
$offset = 0;
			
for ($i = 0; $i<strlen($query); ++$i) 
	switch ($query{$i}) { 
		case '\\':++$i;continue; 
		case '"';case "'";
		if ($query{$i} === $f) { 
			$substring=substr($query,$pos+1,$i-$pos-1);
			$temp=strlen($substring);
			foreach ($replacement as $r)
				$substring=str_replace(" ".$r." ","'".strrev($r)."'",$substring);
				 $f = false;
				            
				 //If there in quotes we had no special words.
				if (strlen($substring)-$temp!=0) {
					$newq=substr($newq,0,$pos+1+$offset).$substring.substr($newq,$i+$offset);
					$offset=$offset+strlen($substring)-$temp;				            
				}
		} elseif ($f) 
			continue; 
		else 
		    	$f = $query{$pos = $i}; 
	}
			    
$query=$newq;

// " INSERT " => "'TRESNI'",
// " blog_id " => "'di_golb'";
 
Сверху