replacing substrings in regex matches with preg_match_all()

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
vapoorize
Forum Newbie
Posts: 22
Joined: Mon Dec 17, 2007 5:35 pm

replacing substrings in regex matches with preg_match_all()

Post by vapoorize »

The preg_replace() function can only replace the full pattern matches. Yes you do have access to the captured substrings and can manipulate them/move them around, but only to replace the full pattern match that it found. I needed a way to replace substrings within the full pattern matches, so I could truly harness the power of regex.
For example, think about how you would replace the second 'l' in hello with something and then replace the first 'l' in laugh with something else:
'hello lalala look over there like to laugh long listen to the large loose'
but with regex you could easily identify those specific l's
'/hel(l)o lalala look over there like to (l)augh long listen to the large loose/'

anyways here' s my solution to replacing substrings from regex matches, i'd like to hear any feedback on better methods of doing this/things to enhance the function

Code: Select all

<?php
function preg_replace_subs($pat,$hay,$replaceArr, $out = false) {
# ie for replaceArr: array(2 => 'two', 4 => 'four')
//$out must have 1 flag set which is offset capture
    if (empty($replaceArr)) {
        die('<br><b>Error:</b><br>Replace Array argument cannot be empty');
    }
    $matches = true;
    if (!$out) {
        $matches = preg_match_all($pat, $hay, $out, PREG_OFFSET_CAPTURE);
    }
    if ($matches && !empty($out[0])) {
        $hayChars = str_split($hay);
        unset($out[0]);
        foreach ($out as $subKey => $subArr) { //each sub $1 -...
            if (isset($replaceArr[$subKey])) {
                foreach ($subArr as $subInfo) { //each match of this sub
                    $sub = $subInfo[0];
                    $subOff = $subInfo[1];
                    $subLen = strlen($sub);
                    if (isset($hayChars[$subOff])) {
                        if ($subLen > 1) {
                            //del rest of positions where old sub existed
                            for ($x = $subOff+1; $x<=(($subOff+$subLen)-1); $x++) {
                                unset($hayChars[$x]);
                            }
                        }
                        //replace substring
                        $hayChars[$subOff] = $replaceArr[$subKey];
                    } else {
                        die('<br><b>Error:</b><br>Cannot replace '.htmlentities($sub).' because it exists in another substring which has already been replaced.');
                    }
                }
            }
        }
        return implode('',$hayChars);
    } else {
        return false;
    } 
}

$pat = '~(hello (<b>)) it is a (wonderful)</b> day<c> (ou(tsi)de) (so lovely)~';
$hay = 'hello <b> it is a wonderful</b> day<c> outside so lovely
hello <b> it is a wonderful</b> day<c> outside so lovely';
$rArr[2] = 'two';
$rArr[4] = 'four';
echo htmlentities(preg_replace_subs($pat,$hay,$rArr));
//outputs: hello two it is a wonderful</b> day<c> four so lovely hello two it is a wonderful</b> day<c> four so lovely
?>
Post Reply