Есть строка, в ней повторяющиеся символы и нужно каждый нужный символ поочередно заменить на значение из массива. Код (Text): $str = 'тут текст %s, а тут число %i и снова текст %s'; $arr1 = array('%s', '%i', '%s'); $arr2 = array('трололо', 123, 'ололо'); В итоге надо получить строку 'тут текст ТРОЛОЛО, а тут число 123 и снова текст ОЛОЛО' Регулярку preg_replace использовать не хочу. Можно ли как нибудь без нее? Спасибо
Код (PHP): $str = 'тут текст %s, а тут число %i и снова текст %v'; $arr1 = array('%s', '%i', '%v'); $arr2 = array('трололо', 123, 'ололо'); echo str_replace($arr1, $arr2, $str); оно? не, не оно ) тогда так: ищем число вхождений символа %s в строку, далее в цикле заменяем той же str_replace
Re: Замена в строке повторяющегося символа на разные значени Можно, получится медленный парсер. Последовательно перебираешь символы. Если встречается % и далее символ s или i, то вставляешь слово из $arr2. На C такое писать нормально, а вот на PHP не стоит.
Re: Замена в строке повторяющегося символа на разные значени именно так работает парсер модыкса, кажется. и очень вероятно - всех шаблонизаторов
Re: Замена в строке повторяющегося символа на разные значени Печально что никак, просто модификаторов может быть много, и на замену кождого вызывать регулярку очень скажется на времени выполнения Добавлено спустя 21 минуту 33 секунды: Re: Замена в строке повторяющегося символа на разные значения так тоже не прокатит, str_replace заменяет все однотипные символы сраз, а не по одному.
Re: Замена в строке повторяющегося символа на разные значени http://php.ru/manual/function.preg-replace-callback.html решает эту задачу
Re: Замена в строке повторяющегося символа на разные значени Решил проблему таким способом Код (Text): if($format[0][$i] == '?s' AND is_string($arg[$i])) { $sp = strpos($sql, $format[0][$i]); $ep = $sp + 2 - strlen($sql); $sql = substr_replace($sql, $arg[$i], $sp, $ep); } if($format[0][$i] == '?i' AND is_int($arg[$i])) { $sp = strpos($sql, $format[0][$i]); $ep = $sp + 2 - strlen($sql); $sql = substr_replace($sql, $arg[$i], $sp, $ep); }
Тот самый "медленный" парсер Код (PHP): <?php $str = 'тут текст %s, а тут число %i и снова текст %s'; //$arr1 = array('%s', '%i', '%s'); $arr2 = array('трололо', 123, 'ололо'); //'тут текст ТРОЛОЛО, а тут число 123 и снова текст ОЛОЛО' echo '<div>входная строка:<br/><code>',$str,'</code></div>',"\n"; $encoding = 'utf-8'; $len = mb_strlen($str, $encoding); define('StateSymbol', 1); define('StateProcent', 2); $state = StateSymbol; $out = '';//выходная строка будет тут $i = 0; $replIndex = 0; $maxRepl = count($arr2); $s = ''; while($i < $len){ $s = mb_substr($str, $i, 1, $encoding); switch ($state){ case StateSymbol: if($s == '%') $state = StateProcent; else $out .= $s; break; case StateProcent: if($s == '%'){//второй процент - игнорировать $state = StateSymbol; $out .= '%%'; }elseif($s == 's'){//вставка строки $out .= $arr2[$replIndex]; $replIndex++; $state = StateSymbol; }elseif($s == 'i'){//вставка числа $out .= $arr2[$replIndex];//конвертация в строку $replIndex++; $state = StateSymbol; } if($replIndex >= $maxRepl){ $out .= mb_substr($str, $i+1, $len-$i-1, $encoding); $i = $len; } break; } $i++; } if($state == StateProcent && $s=='%') $out .= '%'; echo '<div>выходная строка:<br/><code>',$out,'</code></div>',"\n"; PS. Потестил, поправил, и теперь он вовсе не медленный, а очень даже огого.
Re: Замена в строке повторяющегося символа на разные значени т.е. ТС думает что регулярками было бы медленнее? =)
Код (PHP): <?php #error_reporting(-1); #ini_set('display_errors', 'on'); function myreplace($str, array $from, array $to) { if (array_keys($from) != array_keys($to)) throw new Exception('Arrays aren\'t compatible'); $p = null; foreach ($from as $key => $val) { $p = strpos($str, $val, $p); if ($p === false) throw new Exception('Substring not found'); $val_len = strlen($val); $str = substr_replace($str, $to[$key], $p, $val_len); $p += $val_len - strlen($to[$key]) + 1; } return $str; } echo myreplace('тут текст %s, а тут число %i и снова текст %s', array('%s', '%i', '%s'), array('трололо', 123, 'ололо')); только кажется мне $from здесь нафиг лишний
Re: Замена в строке повторяющегося символа на разные значени Судя по функции microtime(), без регулярки в разы быстрее! Добавлено спустя 3 минуты 47 секунд: Re: Замена в строке повторяющегося символа на разные значения Спасибо всем за помощь!
вариант без массива $from Код (PHP): <?php #error_reporting(-1); #ini_set('display_errors', 'on'); function myreplace($str, array $to) { if (preg_match_all('~%[si]~', $str, $matches) != count($to)) throw new Exception('Array not fit pattern'); $from = $matches[0]; $p = null; foreach ($from as $key => $val) { $p = strpos($str, $val, $p); $val_len = strlen($val); // always 2 ? $str = substr_replace($str, $to[$key], $p, $val_len); $p += $val_len - strlen($to[$key]) + 1; } return $str; } echo myreplace('тут текст %s, а тут число %i и снова текст %s', array('трололо', 123, 'ололо')); Добавлено спустя 15 минут 8 секунд: Re: Замена в строке повторяющегося символа на разные значения или так Код (PHP): <?php #error_reporting(-1); #ini_set('display_errors', 'on'); function myreplace($str, array $to) { if (preg_match_all('~%[si]~', $str, $matches) != count($to)) throw new Exception('Array not fit pattern'); reset($to); return preg_replace_callback('~%[si]~', function($matches) use(&$to) { list($key, $val) = each($to); return $val; }, $str); } echo myreplace('тут текст %s, а тут число %i и снова текст %s', array('трололо', 123, 'ололо'));
Re: Замена в строке повторяющегося символа на разные значени Хочу тестовый текст. На котором регулярка медленнее. И регулярку. Автор, дай заценить!
Прошу господа Код (PHP): <?php for($z = 0; $z < 2000; $z++) { $str1 .= "Это тестовая строка содержит: ?s, а так же цифры: ?i и супер-?s<br>"; $str2 .= "Это тестовая строка содержит: ?s, а так же цифры: ?i и супер-?s<br>"; $arg[] = 'ОЛОЛОША'; $arg[] = 123; $arg[] = 'ТЕКСТ'; } $t1=microtime(true); for($k = 0; $k < 50; $k++) { preg_match_all('#\?[sifand]{1}#', $str1, $format); if(count($format[0]) === count($arg)) { for($i =0; $i < count($arg); $i++) { if($format[0][$i] == '?s' AND is_string($arg[$i])) { $sp = strpos($str1, $format[0][$i]); $ep = $sp + 2 - strlen($str1); $str1 = substr_replace($str1, $arg[$i], $sp, $ep); } if($format[0][$i] == '?i' AND is_int($arg[$i])) { $sp = strpos($str1, $format[0][$i]); $ep = $sp + 2 - strlen($str1); $str1 = substr_replace($str1, $arg[$i], $sp, $ep); } else { echo FALSE; } } } //echo $str1; } echo microtime(true) - $t1 . "<br>"; $t2=microtime(true); for($k = 0; $k < 50; $k++) { preg_match_all('#\?[sifand]{1}#', $str2, $format); if(count($format[0]) === count($arg)) { for($i =0; $i < count($arg); $i++) { if($format[0][$i] == '?s' AND is_string($arg[$i])) { $str2 = preg_replace('#\?[sifand]{1}#', $arg[$i], $str2, 1); } if($format[0][$i] == '?i' AND is_int($arg[$i])) { $str2 = preg_replace('#\?[sifand]{1}#', $arg[$i], $str2, 1); } else { echo FALSE; } } } //echo $str2; } echo microtime(true) - $t2 . "<br>"; ?>
Re: Замена в строке повторяющегося символа на разные значени Ну дак я и искал только ту часть кола, которая заменяет
с телефона я плохо разглядел. теперь вижу лучше. код странный. зачем проверять на соответствие количество подмен количеству маркеров? зачем проверять на инт или стринг? это бессмысленно. зачем использовать регулярку, если после нее ты сразу ищешь снова то же самое через стрпос? о_О это вообще бред. что это? что это делает? $ep = $sp + 2 - strlen($str1); зачем? Код (Text): else { echo FALSE; } этот фалс будет выстреливать и на стринги. и ты крутишь для теста в цикле это 50 раз. при этом ты в первой же итерации производишь замену в строке дальше циклы гоняются впустую. мой вариант сравнительное время: 0.60721921920776 1.0821189880371 0.34801602363586 - мой запустить онлайн http://sandbox.onlinephpfunctions.com/code/108952ab28f320b8 ... 1155736e01 Код (PHP): <?php $iter = 50; $str = ''; $replaces = []; $reps = ['i' => [], 's' => []]; for ($z = 0; $z < 500; $z++) { $str .= "Это тестовая строка содержит: ?s, а так же цифры: ?i и супер-?s "; $arg[] = $reps['s'][] = 'ОЛОЛОША'; $arg[] = $reps['s'][] = 'ТЕКСТ'; $arg[] = $reps['i'][] = 123; } $t1 = microtime(true); for ($k = 0; $k < $iter; $k++) { $out = $str; preg_match_all('#\?[sifand]{1}#', $out, $format); if (count($format[0]) === count($arg)) { for ($i = 0; $i < count($arg); $i++) { if ($format[0][$i] == '?s' AND is_string($arg[$i])) { $sp = strpos($out, $format[0][$i]); $ep = $sp + 2 - strlen($out); $out = substr_replace($out, $arg[$i], $sp, $ep); } if ($format[0][$i] == '?i' AND is_int($arg[$i])) { $sp = strpos($out, $format[0][$i]); $ep = $sp + 2 - strlen($out); $out = substr_replace($out, $arg[$i], $sp, $ep); } else { echo FALSE; } } } } echo microtime(true) - $t1 . "\n"; echo $out . "\n\n\n\n\n"; $out = ''; $t2 = microtime(true); for ($k = 0; $k < $iter; $k++) { $out = $str; preg_match_all('#\?[sifand]{1}#', $out, $format); if (count($format[0]) === count($arg)) { for ($i = 0; $i < count($arg); $i++) { if ($format[0][$i] == '?s' AND is_string($arg[$i])) { $out = preg_replace('#\?[sifand]{1}#', $arg[$i], $out, 1); } if ($format[0][$i] == '?i' AND is_int($arg[$i])) { $out = preg_replace('#\?[sifand]{1}#', $arg[$i], $out, 1); } else { echo FALSE; } } } } echo microtime(true) - $t2 . "\n"; echo $out . "\n\n\n\n\n"; $out = ''; $t2 = microtime(true); for ($k = 0; $k < $iter; $k++) { $counter = []; $max = []; foreach ($reps as $key => $val) { $counter[$key] = 0; $max[$key] = count($val); } $out = preg_replace_callback('/\?([sifand])/', function ($matches) use ($reps, &$counter, $max) { $key = $counter[$matches[1]]; $counter[$matches[1]]++; if ($counter[$matches[1]] > $max[$matches[1]]) { $counter[$matches[1]] = 0; } return $reps[$matches[1]][$key]; }, $str); } echo microtime(true) - $t2 . "\n"; echo $out . "\n\n"; $out = ''; и обрати внимание, оба твои варианта не работают как ожидается. и с определённой длинны строки они вообще перестают работать.
Re: Замена в строке повторяющегося символа на разные значени Что-бы убедиться что количество маркеров и количество аргументов соответствую друг другу. Поэтому и стоят разные маркеры, чтобы каждому соответствовал свой тип. В регулярке я выбираю все маркеры в той последовательности в которой они идут и уже передаю в стрпос
Re: Замена в строке повторяющегося символа на разные значени Зачем убеждаться, что соответствуют? я спросил зачем проверять, а не про тип. ты понимаешь, что ты там делаешь? это ж бред =) жуткий. ты просто заново ищешь маркер =) короче я понял я тебе советую более основательно подходить к планированию своих действий.
Re: Замена в строке повторяющегося символа на разные значени Спасибо, прислушаюсь. Возможно виноват уровень знаний.