Page 1 of 1

Re: preg_replace, more than 4

Posted: Thu Mar 10, 2011 11:39 am
by Jonah Bron
Unfortunately, I don't think regex can be used to backreference the number of matches. So, we've got to do sort of a hybrid between using regex and doing it manually.

Code: Select all

preg_match_all('/(\A|1)(0{1,4})(1|\Z)/', $source, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$result = $source;
foreach ($matches as $match) {
    $length = strlen($match[2][0]);
    $offset = $match[2][1];
    $replacement = str_pad('', $length, '1');
    $result = substr_replace($result, $replacement, $offset, $length);
}
This almost works. The problem is, if there are two clumps of zeros of the correct length separated by only one '1', the regexes overlap and it only gets the first one. Still working on it...

Re: preg_replace, more than 4

Posted: Thu Mar 10, 2011 11:46 am
by Jonah Bron
Okay, this works perfectly.

Code: Select all

$source = '11000001100010011000001';
$result = $source;

$searchOffset = 0;
while (preg_match('/(\A|1)(0{1,4})(1|\Z)/', $source, $match, PREG_OFFSET_CAPTURE, $searchOffset)) {
    $length = strlen($match[2][0]);
    $offset = $match[2][1];
    $searchOffset = $offset + $length;
    $replacement = str_pad('', $length, '1');
    $result = substr_replace($result, $replacement, $offset, $length);
}
Do you see how it works? It keeps searching the $source string for a clump of zeros between 1 and 4 in size, making sure there's a one or the beginning before, and a one or the end after. Otherwise it would match larger clumps. PREG_OFFSET_CAPTURE is used so that we know where the match is found (see http://php.net/preg-match). Next, it gets the necessary information from the match, and generates a clump of ones the correct length. Lastly, the replacement is made with substr_replace().

Note that upon every iteration, the $searchOffset is changed to the end of the current match. Otherwise, the loop would go on forever, always returning the first match.

http://php.net/substr-replace
http://php.net/str-pad

Re: preg_replace, more than 4

Posted: Thu Mar 10, 2011 11:55 am
by John Cartwright
Moved to PHP-Code.

Re: preg_replace, more than 4

Posted: Thu Mar 10, 2011 12:26 pm
by AbraCadaver
Someone might be able to suggest a better pattern and I only tested on your test string, but try this:

Code: Select all

$string = '11000001100010011000001'; 
$pattern = '/(?<!0)(0{1,4})(?!0)/e';
$replacement = 'str_repeat("1", strlen("$1"))';

echo preg_replace($pattern, $replacement, $string);
The {1,4} is greedy so it takes as many 0s as it can up to 4 and it is wrapped in negative assertions. The e modifier specifies that the replacement will be PHP code to evaluate.

Re: preg_replace, more than 4

Posted: Thu Mar 10, 2011 3:04 pm
by Jonah Bron
8O that's sweet.

:banghead: forgot about calling functions in the replacement!