Лучший способ восстановить первый экземпляр возможно повторяющегося символа в строке без использования функций preg_ *

Функция, которую я использую, должна обнаружить первый экземпляр символа, и, если символ повторяется, восстановить повторяющуюся подстроку. Например:

$x = 'fhdfhbc::::dcdcdcuttr482rdvcjv:ducvdk:::chjvdbj'; // ---> function should extract ::::

Я не хочу использовать любой из preg_* функции, как я избегаю их, когда это возможно (потому что эти функции медленные). Мое решение в настоящее время это:

$char = ":"; // this would be set as necessary

$char_substring = str_repeat($char, strspn(strstr($x, $char), $char)); // yields ---> ::::

Обратите внимание, что вы не можете использовать strrpos здесь, потому что могут быть (в этом случае) двоеточия на другом конце строки. Ты можешь использовать explodeзатем запустите for или же foreach цикл, объединяющий пустые места, или какой-то вариант этого:

$explode = explode($char, $x);
$substring = $char; // explode array should have 1 less empty member than the repeated character, so need to start with char count of 1
$emptyEncountered = false;
for($i = 0, $count = count($explode); $i < $count; $i++) {
if ($explode[$i]) {
if ($emptyEncountered) break;
} else {
$emptyEncountered = true;
$substring .= $char;
}
}

echo $substring; // ---> ::::

Есть ли лучший способ, чем использовать preg_ *, цикл for / each или str_repeat (strspn (strstr ()))?

0

Решение

Правильный preg_* реализация превзойдет explode подход не только во времени, но и с точки зрения потребления памяти и требуемого распределения.

Единственная реализация, которую я могу придумать, которая является эффективной и которая придерживается ваших ограничений, будет while цикл:

$substring = '';

$i = strpos($haystack, $needle);
do {
$substring .= $needle;
++$i;
}
while (isset($haystack{$i}) && $haystack{$i} === $needle);

return $substring;

Однако у вас уже есть самая эффективная реализация:

return str_repeat($needle, strspn(strstr($haystack, $needle), $needle));

Это также функционально по своей природе.

В ваших реализациях отсутствует обработка ошибок, поэтому while реализация. По моему мнению, это обязательно требуется, но я игнорирую это, потому что вы это делаете.


Результаты на моей машине i7 с Win 10 PHP TS x64 7.1:

$ bench 10000
0.0040609836578369  # str_repeat
0.0044500827789307  # preg_match
0.0046060085296631  # while
0.0050818920135498  # for
0.0052239894866943  # preg_match + preg_quote
0.0079050064086914  # explode

#!/usr/bin/env php
<?php

function bench(callable $cb): void {
global $argv;

$limit = 1000;
if (isset($argv[1]) && is_numeric($argv[1])) {
$limit = (int) $argv[1];
}
elseif (isset($_ENV['LOOP']) && is_numeric($_ENV['LOOP'])) {
$limit = (int) $_ENV['LOOP'];
}

gc_collect_cycles();
gc_disable();
$start = microtime(true);
for ($i = 0; $i < $limit; ++$i) {
$cb();
}
$end = microtime(true);
gc_enable();
gc_collect_cycles();

echo $end - $start, "\n";
}

$haystack = 'fhdfhbc::::dcdcdcuttr482rdvcjv:ducvdk:::chjvdbj';
$needle   = ':';

bench(function () use ($haystack, $needle) {
return str_repeat($needle, strspn(strstr($haystack, $needle), $needle));
});

bench(function () use ($haystack, $needle) {
preg_match("/{$needle}{2,}/", $haystack, $matches);

return $matches[0] ?? '';
});

bench(function () use ($haystack, $needle) {
$substring = '';
$i         = strpos($haystack, $needle);

do {
$substring .= $needle;
++$i;
}
while (isset($haystack{$i}) && $haystack{$i} === $needle);

return $substring;
});

bench(function () use ($haystack, $needle) {
$substring = '';

for ($i = strpos($haystack, $needle); isset($haystack{$i}) && $haystack{$i} === $needle; ++$i) {
$substring .= $needle;
}

return $substring;
});

bench(function () use ($haystack, $needle) {
$needle = preg_quote($needle, '/');

preg_match("/{$needle}{2,}/", $haystack, $matches);

return $matches[0] ?? '';
});

bench(function () use ($haystack, $needle) {
$explode   = explode($needle, $haystack);
$substring = $needle;
$empty     = false;

for ($i = 0, $count = count($explode); $i < $count; $i++) {
if ($explode[$i]) {
if ($empty) {
break;
}
}
else {
$empty     = true;
$substring .= $needle;
}
}

return $substring;
});
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]