preg_replace, more than 4

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
Jonah Bron
DevNet Master
Posts: 2764
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: preg_replace, more than 4

Post 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...
User avatar
Jonah Bron
DevNet Master
Posts: 2764
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: preg_replace, more than 4

Post 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
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Re: preg_replace, more than 4

Post by John Cartwright »

Moved to PHP-Code.
User avatar
AbraCadaver
DevNet Master
Posts: 2572
Joined: Mon Feb 24, 2003 10:12 am
Location: The Republic of Texas
Contact:

Re: preg_replace, more than 4

Post 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.
mysql_function(): WARNING: This extension is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQLextension should be used. See also MySQL: choosing an API guide and related FAQ for more information.
User avatar
Jonah Bron
DevNet Master
Posts: 2764
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: preg_replace, more than 4

Post by Jonah Bron »

8O that's sweet.

:banghead: forgot about calling functions in the replacement!
Post Reply