За последние 24 часа нас посетили 21298 программистов и 1690 роботов. Сейчас ищет 1831 программист ...

Заменить все вхождения, кроме первого

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

  1. JohnJ

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

    С нами с:
    2 июл 2009
    Сообщения:
    9
    Симпатии:
    0
    Здравствуйте!
    Задача, найти все вхождения подстроки в строку и заменить их все, кроме первого!
    Например, дана строка:
    Нужно с помощью preg_replace заменить все вхождения bb на СС, например.
    Абсолютно все - не сложно, вот так:
    Код (Text):
    1. "/bb/i", "CC"
    . В итоге получается:
    Все, кроме первого, у меня не выходит. По идее нужно искать по такому принципу: если перед найденным bb через любое количество символов есть ещё один bb, значит найденный - не первый и его можно заменить. Реализую так:
    Код (Text):
    1. "/(bb.*)bb/i", "$1CC"
    В итогде получается
    Может это и типовая задачка, но нигде не нашёл решения и сам додуматься не могу как правильно и почему мой вариант не работает...

    Заранее благодарю за помощь.
     
  2. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    PHP:
    1. <?php
    2.     $what = 'bb';
    3.     $with = 'xx';
    4.     $string = 'aa-bb-cc aa-bb-cc aa-bb-cc aa-bb-cc';
    5.     $regexp = "/($what.*?)$what/";
    6.     while (preg_match($regexp, $string)) {
    7.         $string = preg_replace($regexp, '$1'.$with, $string);
    8.     }
    9.     echo $string; // aa-bb-cc aa-xx-cc aa-xx-cc aa-xx-cc
    10. ?>
    11.  
    Оно?
     
  3. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    при том стоит заметить, что при одинаковом результате /($what.*)$what/ может быть в сотни раз медленнее, чем /($what.*?)$what/:

    PHP:
    1. <?php
    2.     $s = microtime(1);
    3.     $what = 'bb';
    4.     $with = 'xx';
    5.     $string = 'aa-bb-cc ';
    6.     $string = str_repeat ($string, 5000);
    7.     /***
    8.       * 0.0467569828033
    9.       * 0.0468139648438
    10.       * 0.0451989173889
    11.       */ $regexp = "/($what.*?)$what/";
    12.     /***
    13.       * 13.2560789585
    14.       * 13.9170439243
    15.       * 13.7839291096
    16.       */ $regexp = "/($what.*)$what/";
    17.     while (preg_match($regexp, $string)) {
    18.         $string = preg_replace ($regexp, '$1'.$with, $string);
    19.     }
    20.     echo (microtime(1) - $s);
    21. ?>
     
  4. JohnJ

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

    С нами с:
    2 июл 2009
    Сообщения:
    9
    Симпатии:
    0
    Не, с жадностью вчера тоже разобрался. Всё-равно не работает, поэтому не стал писать. Причём я сейчас тренируюсь на bb, чтобы понять принцип, а потом у меня будут теги, все с разными параметрами (например, тег IMG с параметрами src). Поэтому через str_replace не получится обойтись. Если только не сделать preg_match_all, получить массив всех вариаций bb, первый не заменять, а остальные через str_replace?
    Но даже если так получится, всё-равно теперь интересно, какое должно быть регулярное выражение для preg_replace, чтобы работал вышеприведёный пример с bb?
     
  5. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    JohnJ, а чем не устраивает тот код, который я предложил?
     
  6. JohnJ

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

    С нами с:
    2 июл 2009
    Сообщения:
    9
    Симпатии:
    0
    TheShock
    сейчас испытаю его в деле :)
    Мне не понятно, зачем нужен цикл? Я думал preg_replace итак проходит всю строку.
     
  7. JohnJ

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

    С нами с:
    2 июл 2009
    Сообщения:
    9
    Симпатии:
    0
    делаю так:
    PHP:
    1. <?php
    2. $pregm[] = array("/(bb.*?)bb/i", '$1'."CC");
    3.  
    4. foreach($pregm as $preg)
    5. {
    6. echo "<DIV style='overflow: auto; width: 100%; max-height: 300px;'>";
    7.  while (preg_match($preg[0], $txt))
    8.  {
    9.     $txt = preg_replace($preg[0], $preg[1], $txt);
    10.  }
    11.  echo $txt."<BR>";
    12. echo "</DIV>";
    13. }
    14. ?>
    15.  
    Заменяет все варианты, даже первый....
    из
    получаем
     
  8. JohnJ

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

    С нами с:
    2 июл 2009
    Сообщения:
    9
    Симпатии:
    0
    Заработало. Благодарю за помощь.
    Я ошибся сам, во-первых, поэтому все элементы заменялись. Во-вторых, нужно ставить модификаторы /is, потому что строка берётся из файла в несколько строчек.
    Радует, что изначально я подобрал примерно правильное регулярное выражение :) Жаль только не додумался до цикла...