За последние 24 часа нас посетили 29599 программистов и 1817 роботов. Сейчас ищут 815 программистов ...

Замена в строке повторяющегося символа на разные значения

Тема в разделе "PHP для новичков", создана пользователем qtk, 18 дек 2013.

  1. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Есть строка, в ней повторяющиеся символы и нужно каждый нужный символ поочередно заменить на значение из массива.
    Код (Text):
    1.  $str = 'тут текст %s, а тут число %i и снова текст %s';
    2.  $arr1 = array('%s', '%i', '%s');
    3.  $arr2 = array('трололо', 123, 'ололо');
    В итоге надо получить строку 'тут текст ТРОЛОЛО, а тут число 123 и снова текст ОЛОЛО'
    Регулярку preg_replace использовать не хочу. Можно ли как нибудь без нее? Спасибо
     
  2. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    Код (PHP):
    1. $str = 'тут текст %s, а тут число %i и снова текст %v';
    2. $arr1 = array('%s', '%i', '%v');
    3. $arr2 = array('трололо', 123, 'ололо');
    4.  
    5. echo str_replace($arr1, $arr2, $str);
    оно?

    не, не оно )

    тогда так: ищем число вхождений символа %s в строку, далее в цикле заменяем той же str_replace
     
  3. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Re: Замена в строке повторяющегося символа на разные значени

    тогда ой
     
  4. YSandro

    YSandro Старожил

    С нами с:
    7 апр 2011
    Сообщения:
    2.523
    Симпатии:
    2
    Re: Замена в строке повторяющегося символа на разные значени

    Можно, получится медленный парсер. Последовательно перебираешь символы. Если встречается % и далее символ s или i, то вставляешь слово из $arr2.
    На C такое писать нормально, а вот на PHP не стоит.
     
  5. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Re: Замена в строке повторяющегося символа на разные значени

    именно так работает парсер модыкса, кажется. :D
    и очень вероятно - всех шаблонизаторов
     
  6. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Re: Замена в строке повторяющегося символа на разные значени

    Печально что никак, просто модификаторов может быть много, и на замену кождого вызывать регулярку очень скажется на времени выполнения

    Добавлено спустя 21 минуту 33 секунды:
    Re: Замена в строке повторяющегося символа на разные значения
    так тоже не прокатит, str_replace заменяет все однотипные символы сраз, а не по одному.
     
  7. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
  8. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Re: Замена в строке повторяющегося символа на разные значени

    Решил проблему таким способом
    Код (Text):
    1. if($format[0][$i] == '?s' AND is_string($arg[$i]))
    2.                     {
    3.                         $sp = strpos($sql, $format[0][$i]);
    4.                         $ep = $sp + 2 - strlen($sql);
    5.                         $sql = substr_replace($sql, $arg[$i], $sp, $ep);
    6.                     }
    7.                     if($format[0][$i] == '?i' AND is_int($arg[$i]))
    8.                     {
    9.                         $sp = strpos($sql, $format[0][$i]);
    10.                         $ep = $sp + 2 - strlen($sql);
    11.                         $sql = substr_replace($sql, $arg[$i], $sp, $ep);
    12.                     }
     
  9. YSandro

    YSandro Старожил

    С нами с:
    7 апр 2011
    Сообщения:
    2.523
    Симпатии:
    2
    Тот самый "медленный" парсер :)
    Код (PHP):
    1. <?php
    2. $str = 'тут текст %s, а тут число %i и снова текст %s';
    3. //$arr1 = array('%s', '%i', '%s');
    4. $arr2 = array('трололо', 123, 'ололо');
    5. //'тут текст ТРОЛОЛО, а тут число 123 и снова текст ОЛОЛО'
    6.  
    7. echo '<div>входная строка:<br/><code>',$str,'</code></div>',"\n";
    8.  
    9. $encoding = 'utf-8';
    10. $len = mb_strlen($str, $encoding);
    11.  
    12. define('StateSymbol', 1);
    13. define('StateProcent', 2);
    14. $state = StateSymbol;
    15.  
    16. $out = '';//выходная строка будет тут
    17. $i = 0;
    18. $replIndex = 0;
    19. $maxRepl = count($arr2);
    20. $s = '';
    21.  
    22. while($i < $len){
    23.     $s = mb_substr($str, $i, 1, $encoding);
    24.     switch ($state){
    25.         case StateSymbol:
    26.             if($s == '%')
    27.                 $state = StateProcent;
    28.             else
    29.                 $out .= $s;
    30.             break;
    31.         case StateProcent:
    32.             if($s == '%'){//второй процент - игнорировать
    33.                 $state = StateSymbol;
    34.                 $out .= '%%';
    35.             }elseif($s == 's'){//вставка строки
    36.                 $out .= $arr2[$replIndex];
    37.                 $replIndex++;
    38.                 $state = StateSymbol;
    39.             }elseif($s == 'i'){//вставка числа
    40.                 $out .= $arr2[$replIndex];//конвертация в строку
    41.                 $replIndex++;
    42.                 $state = StateSymbol;
    43.             }
    44.             if($replIndex >= $maxRepl){
    45.                 $out .= mb_substr($str, $i+1, $len-$i-1, $encoding);
    46.                 $i = $len;
    47.             }
    48.             break;
    49.     }
    50.     $i++;
    51. }
    52. if($state == StateProcent && $s=='%') $out .= '%';
    53. echo '<div>выходная строка:<br/><code>',$out,'</code></div>',"\n";
    PS. Потестил, поправил, и теперь он вовсе не медленный, а очень даже огого.
     
  10. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Re: Замена в строке повторяющегося символа на разные значени

    т.е. ТС думает что регулярками было бы медленнее? =)
     
  11. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    Код (PHP):
    1. <?php
    2.  
    3. #error_reporting(-1);
    4. #ini_set('display_errors', 'on');
    5.  
    6. function myreplace($str, array $from, array $to)
    7. {
    8.     if (array_keys($from) != array_keys($to)) throw new Exception('Arrays aren\'t compatible');
    9.     $p = null;
    10.     foreach ($from as $key => $val) {
    11.         $p = strpos($str, $val, $p);
    12.         if ($p === false) throw new Exception('Substring not found');
    13.         $val_len = strlen($val);
    14.         $str = substr_replace($str, $to[$key], $p, $val_len);
    15.         $p += $val_len - strlen($to[$key]) + 1;
    16.     }
    17.     return $str;
    18. }
    19.  
    20. echo myreplace('тут текст %s, а тут число %i и снова текст %s', 
    21.   array('%s', '%i', '%s'),
    22.   array('трололо', 123, 'ололо'));
    только кажется мне $from здесь нафиг лишний
     
  12. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Re: Замена в строке повторяющегося символа на разные значени

    Судя по функции microtime(), без регулярки в разы быстрее!

    Добавлено спустя 3 минуты 47 секунд:
    Re: Замена в строке повторяющегося символа на разные значения
    Спасибо всем за помощь!
     
  13. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    вариант без массива $from
    Код (PHP):
    1. <?php
    2.  
    3. #error_reporting(-1);
    4. #ini_set('display_errors', 'on');
    5.  
    6. function myreplace($str, array $to)
    7. {
    8.     if (preg_match_all('~%[si]~', $str, $matches) != count($to))
    9.         throw new Exception('Array not fit pattern');
    10.     $from = $matches[0];
    11.     $p = null;
    12.     foreach ($from as $key => $val) {
    13.         $p = strpos($str, $val, $p);
    14.         $val_len = strlen($val); // always 2 ?
    15.         $str = substr_replace($str, $to[$key], $p, $val_len);
    16.         $p += $val_len - strlen($to[$key]) + 1;
    17.     }
    18.     return $str;
    19. }
    20.  
    21. echo myreplace('тут текст %s, а тут число %i и снова текст %s', 
    22.   array('трололо', 123, 'ололо'));
    Добавлено спустя 15 минут 8 секунд:
    Re: Замена в строке повторяющегося символа на разные значения
    или так
    Код (PHP):
    1. <?php
    2.  
    3. #error_reporting(-1);
    4. #ini_set('display_errors', 'on');
    5.  
    6. function myreplace($str, array $to)
    7. {
    8.     if (preg_match_all('~%[si]~', $str, $matches) != count($to))
    9.         throw new Exception('Array not fit pattern');
    10.     reset($to);
    11.     return preg_replace_callback('~%[si]~', function($matches) use(&$to)
    12.       {
    13.         list($key, $val) = each($to);
    14.         return $val;
    15.       }, 
    16.       $str);
    17. }
    18.  
    19. echo myreplace('тут текст %s, а тут число %i и снова текст %s', array('трололо', 123, 'ололо'));
     
  14. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Re: Замена в строке повторяющегося символа на разные значени

    Хочу тестовый текст. На котором регулярка медленнее. И регулярку. Автор, дай заценить!
     
  15. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Прошу господа
    Код (PHP):
    1. <?php
    2. for($z = 0; $z < 2000; $z++)
    3. {
    4.     $str1 .= "Это тестовая строка содержит: ?s, а так же цифры: ?i и супер-?s<br>";
    5.     $str2 .= "Это тестовая строка содержит: ?s, а так же цифры: ?i и супер-?s<br>";
    6.     $arg[] = 'ОЛОЛОША';
    7.     $arg[] = 123;
    8.     $arg[] = 'ТЕКСТ';
    9. }
    10. $t1=microtime(true);
    11. for($k = 0; $k < 50; $k++)
    12. {
    13.     preg_match_all('#\?[sifand]{1}#', $str1, $format);
    14.     if(count($format[0]) === count($arg))
    15.     {
    16.         for($i =0; $i < count($arg); $i++)
    17.         {
    18.             if($format[0][$i] == '?s' AND is_string($arg[$i]))
    19.             {
    20.                 $sp = strpos($str1, $format[0][$i]);
    21.                 $ep = $sp + 2 - strlen($str1);
    22.                 $str1 = substr_replace($str1, $arg[$i], $sp, $ep);
    23.             }
    24.             if($format[0][$i] == '?i' AND is_int($arg[$i]))
    25.             {
    26.                 $sp = strpos($str1, $format[0][$i]);
    27.                 $ep = $sp + 2 - strlen($str1);
    28.                 $str1 = substr_replace($str1, $arg[$i], $sp, $ep);
    29.             }
    30.             else
    31.             {
    32.                 echo FALSE;
    33.             }
    34.         }
    35.     }
    36.     //echo $str1;
    37. }            
    38. echo microtime(true) - $t1 . "<br>";
    39.  
    40.  
    41. $t2=microtime(true);
    42. for($k = 0; $k < 50; $k++)
    43. {
    44.     preg_match_all('#\?[sifand]{1}#', $str2, $format);
    45.     if(count($format[0]) === count($arg))
    46.     {
    47.         for($i =0; $i < count($arg); $i++)
    48.         {
    49.             if($format[0][$i] == '?s' AND is_string($arg[$i]))
    50.             {
    51.                 $str2 = preg_replace('#\?[sifand]{1}#', $arg[$i], $str2, 1);
    52.             }
    53.             if($format[0][$i] == '?i' AND is_int($arg[$i]))
    54.             {
    55.                 $str2 = preg_replace('#\?[sifand]{1}#', $arg[$i], $str2, 1);
    56.             }
    57.             else
    58.             {
    59.                 echo FALSE;
    60.             }
    61.         }
    62.     }
    63.     //echo $str2;
    64. }            
    65. echo microtime(true) - $t2 . "<br>";
    66. ?>
     
  16. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Re: Замена в строке повторяющегося символа на разные значени

    Они же одинаковые
     
  17. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Re: Замена в строке повторяющегося символа на разные значени

    Ну дак я и искал только ту часть кола, которая заменяет :)
     
  18. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    с телефона я плохо разглядел. теперь вижу лучше.

    код странный.
    зачем проверять на соответствие количество подмен количеству маркеров?
    зачем проверять на инт или стринг? это бессмысленно.
    зачем использовать регулярку, если после нее ты сразу ищешь снова то же самое через стрпос? о_О это вообще бред. что это?
    что это делает? $ep = $sp + 2 - strlen($str1); зачем?
    Код (Text):
    1.  else {
    2.       echo FALSE;
    3.     }
    этот фалс будет выстреливать и на стринги.

    и ты крутишь для теста в цикле это 50 раз. при этом ты в первой же итерации производишь замену в строке :D дальше циклы гоняются впустую.

    мой вариант
    сравнительное время:
    0.60721921920776
    1.0821189880371
    0.34801602363586 - мой

    запустить онлайн http://sandbox.onlinephpfunctions.com/code/108952ab28f320b8 ... 1155736e01

    Код (PHP):
    1. <?php
    2. $iter = 50;
    3. $str = '';
    4. $replaces = [];
    5. $reps = ['i' => [], 's' => []];
    6. for ($z = 0; $z < 500; $z++) {
    7.   $str .= "Это тестовая строка содержит: ?s, а так же цифры: ?i и супер-?s ";
    8.   $arg[] = $reps['s'][] = 'ОЛОЛОША';
    9.   $arg[] = $reps['s'][] = 'ТЕКСТ';
    10.   $arg[] = $reps['i'][] = 123;
    11.  
    12. }
    13.  
    14.  
    15. $t1 = microtime(true);
    16. for ($k = 0; $k < $iter; $k++) {
    17.   $out = $str;
    18.   preg_match_all('#\?[sifand]{1}#', $out, $format);
    19.   if (count($format[0]) === count($arg)) {
    20.     for ($i = 0; $i < count($arg); $i++) {
    21.       if ($format[0][$i] == '?s' AND is_string($arg[$i])) {
    22.         $sp = strpos($out, $format[0][$i]);
    23.         $ep = $sp + 2 - strlen($out);
    24.         $out = substr_replace($out, $arg[$i], $sp, $ep);
    25.       }
    26.       if ($format[0][$i] == '?i' AND is_int($arg[$i])) {
    27.         $sp = strpos($out, $format[0][$i]);
    28.         $ep = $sp + 2 - strlen($out);
    29.         $out = substr_replace($out, $arg[$i], $sp, $ep);
    30.       } else {
    31.         echo FALSE;
    32.       }
    33.     }
    34.   }
    35. }
    36. echo microtime(true) - $t1 . "\n";
    37. echo $out . "\n\n\n\n\n";
    38. $out = '';
    39.  
    40. $t2 = microtime(true);
    41. for ($k = 0; $k < $iter; $k++) {
    42.   $out = $str;
    43.   preg_match_all('#\?[sifand]{1}#', $out, $format);
    44.   if (count($format[0]) === count($arg)) {
    45.     for ($i = 0; $i < count($arg); $i++) {
    46.       if ($format[0][$i] == '?s' AND is_string($arg[$i])) {
    47.         $out = preg_replace('#\?[sifand]{1}#', $arg[$i], $out, 1);
    48.       }
    49.       if ($format[0][$i] == '?i' AND is_int($arg[$i])) {
    50.         $out = preg_replace('#\?[sifand]{1}#', $arg[$i], $out, 1);
    51.       } else {
    52.         echo FALSE;
    53.       }
    54.     }
    55.   }
    56. }
    57. echo microtime(true) - $t2 . "\n";
    58. echo $out . "\n\n\n\n\n";
    59. $out = '';
    60.  
    61. $t2 = microtime(true);
    62. for ($k = 0; $k < $iter; $k++) {
    63.   $counter = [];
    64.   $max = [];
    65.   foreach ($reps as $key => $val) {
    66.     $counter[$key] = 0;
    67.     $max[$key] = count($val);
    68.   }
    69.   $out = preg_replace_callback('/\?([sifand])/', function ($matches) use ($reps, &$counter, $max) {
    70.     $key = $counter[$matches[1]];
    71.     $counter[$matches[1]]++;
    72.     if ($counter[$matches[1]] > $max[$matches[1]]) {
    73.       $counter[$matches[1]] = 0;
    74.     }
    75.     return $reps[$matches[1]][$key];
    76.   }, $str);
    77. }
    78. echo microtime(true) - $t2 . "\n";
    79. echo $out . "\n\n";
    80. $out = '';
    81.  
    и обрати внимание, оба твои варианта не работают как ожидается. и с определённой длинны строки они вообще перестают работать.
     
  19. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Re: Замена в строке повторяющегося символа на разные значени

    Что-бы убедиться что количество маркеров и количество аргументов соответствую друг другу.
    Поэтому и стоят разные маркеры, чтобы каждому соответствовал свой тип.
    В регулярке я выбираю все маркеры в той последовательности в которой они идут и уже передаю в стрпос
     
  20. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Re: Замена в строке повторяющегося символа на разные значени

    Зачем убеждаться, что соответствуют?

    я спросил зачем проверять, а не про тип. ты понимаешь, что ты там делаешь? это ж бред =) жуткий.

    ты просто заново ищешь маркер =)

    короче я понял

    я тебе советую более основательно подходить к планированию своих действий.
     
  21. qtk

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

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Re: Замена в строке повторяющегося символа на разные значени

    Спасибо, прислушаюсь. Возможно виноват уровень знаний.