За последние 24 часа нас посетили 17445 программистов и 1960 роботов. Сейчас ищут 905 программистов ...

Заменить в тексте, но пропустить замену в тегах?

Тема в разделе "PHP для новичков", создана пользователем User123, 9 мар 2018.

Метки:
  1. User123

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

    С нами с:
    23 янв 2015
    Сообщения:
    47
    Симпатии:
    2
    Есть такой код, заменяет один раз в тексте:
    Код (Text):
    1. function str_replace_once($search, $replace, $text)
    2. {
    3. $pos = strpos($text, $search);
    4. return $pos!==false ? substr_replace($text, $replace, $pos, strlen($search)) : $text;
    5. }
    6.  
    7. $str = 'Helo World!';
    8. $str = str_replace_once('l', 'll', $str);
    9. // результат 'Hello World!';
    подскажите как в условия добавить исключения, чтобы замены не происходили если текст будет в тегах
    то есть если
    Код (Text):
    1. $str = '<a href="(тут любая ссылка)">Helo World!</a>';
    то замена не произойдет
     
  2. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.593
    Симпатии:
    362
    @User123, во-первых, теги - они разные бывают. Интересуют все теги, или только <a?
    Во-вторых - игнорировать ли подходящий для замены текст, если он находится после тегов?
     
  3. User123

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

    С нами с:
    23 янв 2015
    Сообщения:
    47
    Симпатии:
    2
    да, пропускать текст если он только в тегах <a>
    если после тегов нужно заменить, не важно до или после тегов, один раз заменить
     
  4. nospiou

    nospiou Старожил

    С нами с:
    4 фев 2018
    Сообщения:
    3.400
    Симпатии:
    510
    https://php.ru/manual/function.preg-replace.html
     
  5. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.593
    Симпатии:
    362
    @User123, или вариант:
    PHP:
    1. function str_replace_once($search, $replace, $text)
    2. {
    3.     $tagPos2 = 0;
    4.     do{
    5.         $pos = strpos($text, $search, $tagPos2);
    6.         $tagPos1 = strpos($text, '<a', $tagPos2);
    7.         $tagPos2 = strpos($text, '</a>', $tagPos2 + 1);
    8.         var_dump($pos, $tagPos1, $tagPos2);
    9.     } while($tagPos1 !== false && $tagPos2 !== false && $pos !== false && ($pos >= $tagPos1 && $pos <= $tagPos2));
    10.     return $pos !== false ? substr_replace($text, $replace, $pos, strlen($search)) : $text;
    11. }
     
    User123 нравится это.
  6. nospiou

    nospiou Старожил

    С нами с:
    4 фев 2018
    Сообщения:
    3.400
    Симпатии:
    510
    Вот извращенец:)
    PHP:
    1. $str = preg_replace('/(<.*?>)?('.$old_val.')/', '${1}'.$new_val, $str);
     
  7. nospiou

    nospiou Старожил

    С нами с:
    4 фев 2018
    Сообщения:
    3.400
    Симпатии:
    510
    Так по универсальнее будет.
    PHP:
    1. $str = preg_replace('/(<.*?>.*?)?('.$old_val.')/', '${1}'.$new_val, $str);
     
  8. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.593
    Симпатии:
    362
    @nospiou, было уточнение, что тег <a> надо учитывать. Параграфы и прочие div'ы - ни при чём.
     
  9. nospiou

    nospiou Старожил

    С нами с:
    4 фев 2018
    Сообщения:
    3.400
    Симпатии:
    510
    Никто не мешает добавить один символ. Регулярка не трогает ничего внутри тегов < вот тут >
    PHP:
    1. $str = preg_replace('/(<a.*?>.*?)?('.$old_val.')/', '${1}'.$new_val, $str);
    Я понял к чему ты. Нужно было <a>ТУТ</a> )
    PHP:
    1. $str = preg_replace('/(<a.*?>.*?<\/a>.*?)?('.$old_val.')/', '${1}'.$new_val, $str);
     
    #9 nospiou, 16 мар 2018
    Последнее редактирование: 16 мар 2018
  10. Emilien

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

    С нами с:
    30 июн 2016
    Сообщения:
    246
    Симпатии:
    156
    Там подвох в том, что если совпадение не найдено, начальная позиция смещается к следующему символу текста, после чего регулярное выражение применяется заново.
    В результате текст и внутри тега тож заменит.
    PHP:
    1. $old_val = 'text';
    2. $new_val = '----';
    3. $str = " $old_val <a $old_val > $old_val </a> ";
    4.  
    5. $str = preg_replace('/(<a.*?>.*?<\/a>.*?)?('.$old_val.')/', '${1}'.$new_val, $str);
    Решить можно с помощью (*SKIP) и (*FAIL) http://pcre.org/original/doc/html/pcresyntax.html#SEC23
    PHP:
    1. $str = preg_replace('~'.$old_val.'|<a.*?</a>(*SKIP)(*F)~s', $new_val, $str);
     
  11. keren

    keren Новичок

    С нами с:
    15 ноя 2017
    Сообщения:
    513
    Симпатии:
    42
    Там не в этом причина, если даже регулярку (<a.*?>.*?<\/a>.*?) заменить на пустые скобки () результат будет тот-же:
    PHP:
    1. $old_val = 'text';
    2. $new_val = '----';
    3. $str = " $old_val <a $old_val > $old_val </a> ";
    4. echo preg_replace('/()('.$old_val.')/', '${1}'.$new_val, $str);
    5. //---- <a ---- > ---- </a>