За последние 24 часа нас посетили 22684 программиста и 1056 роботов. Сейчас ищут 722 программиста ...

Нужно пояснение знатаков, не жадный режим.

Тема в разделе "Регулярные выражения", создана пользователем Rassol2, 8 июл 2019.

  1. Rassol2

    Rassol2 Новичок

    С нами с:
    8 июл 2019
    Сообщения:
    31
    Симпатии:
    1
    Здравствуйте.
    Только что обнаружил неприятную вещь и хотел бы получить совет от знатоков.

    Суть проблемы.
    При использовании (.*?) В не жадном режиме. И после этих скобок мы ни указываем ни один символ, то данное правило не срабатывает.

    Примеры.

    PHP:
    1. $text = 'Привет! страт удали меня стоп а этот стоп не удалять.';
    2.  
    3.   $value = preg_replace('#страт(.*?)стоп#su', '', $text);
    4.   echo $value;
    Результат верный.
    Привет! а этот стоп не удалять.


    А теперь немного меняем правило.
    PHP:
    1. $text = 'Привет! страт удали меня стоп а этот стоп не удалять.';
    2.  
    3.   $value = preg_replace('#страт(.*?)#su', '', $text);
    4.   echo $value;
    Результат
    Привет! удали меня стоп а этот стоп не удалять.

    то есть видно что условие (.*?) не сработало. Как поправить что бы оно отрабатывало до конца всего текста.

    Если оставить по умолчанию жадный режим. то есть вот так (.*)
    то первое правило отработается неверно
    PHP:
    1. $text = 'Привет! страт удали меня стоп а этот стоп не удалять.';
    2.  
    3.   $value = preg_replace('#страт(.*)стоп#su', '', $text);
    4.   echo $value;
    Результат
    Привет! не удалять.

    Проблема в том что это правило составляется пользователем, и входной текст заранее не известен.
    И условия правила.
    Это некая функция которая помогает пользователям форматировать текст.
    Пользователь вводит страт{skip}стоп | Удалить
    И человеко понятное правило преобразовываю в регулярку которая делает удаление.

    Подытожу.
    Как в регулярный выражениях сделать что бы если после скобок (.*?) ничего не написано, они отрабатывали до конца текста. А если есть что то, то до первого совпадения.
     
  2. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.744
    Симпатии:
    1.319
    Адрес:
    Лень
    PHP:
    1. <?php
    2.  
    3. $fun = function ( string ...$string ): string
    4. {
    5.   $first = strpos ( $string[0], $string[1] ) + strlen ( $string[1] );
    6.  
    7.   $last = strpos ( substr ( $string[0], $first ), $string[2] );
    8.  
    9.   return strtr ( $string[0], [ $string[1].substr ( $string[0], $first, $last ).$string[2] => '' ] );
    10. };
    11.  
    12. echo $fun( 'Привет! страт удали меня стоп а этот стоп не удалять.', 'страт', 'стоп' );
    --- Добавлено ---
    PHP:
    1. <?php
    2.  
    3. $fun = function ( string ...$string ): string
    4. {
    5.   return trim ( substr ( $string[0], 0, strpos ( $string[0], $string[1] ) ), ' ' ) . substr ( $string[0], strpos ( $string[0], $string[2] ) + strlen ( $string[2] ) );
    6. };
    7.  
    8. echo $fun( 'Привет! страт удали меня стоп а этот стоп не удалять.', 'страт', 'стоп' );
     
  3. miltorg

    miltorg Активный пользователь

    С нами с:
    7 апр 2019
    Сообщения:
    375
    Симпатии:
    12
    Адрес:
    Калининград
    Указать конец строки?

    страт(.*?)$
     
  4. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    проверяй наличие СТОП. если есть, возвращай одно регулярное выражение, если нет - другое.
    в чем проблема?
     
  5. Rassol2

    Rassol2 Новичок

    С нами с:
    8 июл 2019
    Сообщения:
    31
    Симпатии:
    1
    Проблема в том что на стороне клиента есть форма для вода правил в понятном для обычного человека формате.
    А именно.
    Любой текст|На что заменить.

    И здесь применяется спец тег {skip} который значит любой текст. Или его отсутствие.
    Так вот у меня есть проблемы в понимании, как реализовать учитывая то что {skip} в правой стороне может быть как один так и 1000

    Сейчас все работает так.
    PHP:
    1.     //Фунция составления герулярного выражения для левой части поиск замена
    2.     public function pregRegLeft($data){
    3.  
    4.         //Отлавливаем регулярные вырежения в правилах поиск замена
    5.         if(preg_match('#^\{reg\[(.*)\]\}$#', $data, $reg)){
    6.          
    7.             $reg = htmlspecialchars_decode($reg[1]);
    8.  
    9.         }else{
    10.          
    11.             $reg = preg_quote(htmlspecialchars_decode($data), '#');
    12.             //Что заменяем
    13.             $what = ['\{skip\}'];
    14.             //Чем заменяем
    15.             $than = ['(.*?)'];
    16.  
    17.             //Замена
    18.             $reg = str_ireplace($what, $than, $reg);
    19.             //Формируем полноценный патерн
    20.             $reg = '#'.$reg.'#su';
    21.         }
    22.  
    23.         return $reg;
    24.     }
    По сути в этой части кода выполняется найди {skip} и замени его на (.*?)
    При подходу с проверкой есть ли вторая или больше частей. Это довольно сложно.

    И пока хотел бы узнать нету ли в регуляторах какого то флага при включении которого можно было бы заставить (.*?) при отсутствии второй части совпадать со всем оставшимся текстом.
    --- Добавлено ---
    Да но никто не гарантирует что после (.*?) будет именно конец строки.
     
  6. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    @Rassol2, есть ещё "или". Например: страт(.*?)(?:стоп|$)
     
    Rassol2 нравится это.
  7. Rassol2

    Rassol2 Новичок

    С нами с:
    8 июл 2019
    Сообщения:
    31
    Симпатии:
    1
    вот кстати про или, я не подумал спасибо попробую отпишусь.
     
  8. vikrorpert

    vikrorpert Активный пользователь

    С нами с:
    13 окт 2010
    Сообщения:
    984
    Симпатии:
    10