Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to preg_replace_all in the large amount of data

I just making an upgrade script for replacing all the MODX snippet tags to a newer format:

Old one: [~123~]

New one: [[~123]]

(of course, 123 - it is an example — there are a lot of different numbers)

Also I wanted to replace all the custom old snippets to a newer ones:

Old snippet format:

[!MySnippetName? &param1=`value1` &param2=`value2` !]

New one:

[[!MySnippetName? &param1=`value1` &param2=`value2` ]]

(of course, &param1=value1 &param2=value2 is just an example and it is different in real snippets)

How to use a preg_replace function to make a global replacements? I supposed to create like this:

$doc[ 'content' ] = $this->preg_replace_all(
        array(
                '/\[~([0-9]+)~\]/',
                '\[!LatestUpdates(.*)!\]',
                '\[!ArticleSummary(.*)!\]',
            ), array(
                '[[~\1]]',
                '[[!LatestUpdates\1]]',
                '[[!ArticleSummary\1]]',
            ),
            $doc[ 'content' ]
        );

preg_replace_all function:

private function preg_replace_all( $find, $replacement, $s )
{
    while(preg_match($find, $s)) {
        $s = preg_replace($find, $replacement, $s);
    }
    return $s;
}

But it doesn't work. Please help to figure out the problem. Thanks in advance.

like image 286
Serhii Matrunchyk Avatar asked Feb 12 '23 16:02

Serhii Matrunchyk


1 Answers

The preg_replace function performs already a global replacement and since only matching substrings are replaced, you don't need to test the existence of these substrings with preg_match.

You can reduce the three patterns to only one pattern:

$pattern = '/\[(?|(!LatestUpdates|!ArticleSummary)(.*?)!]|(~)([0-9]+)~])/';
$replacement = '[[$1$2]]';
$doc['content'] = preg_replace($pattern, $replacement, $doc['content']);

This pattern use the branch reset feature that allows capture groups to have the same number in each alternative.

If it is possible (if it doesn't change tags you want to preserve), you can do the same with strtr:

$doc['content'] = strtr($doc['content'], array('[!'=>'[[!', '[~'=>'[[~', '~]'=>']]', '!]'=>']]'));

Note that if you can use it, don't hesitate since this way is much faster.

like image 145
Casimir et Hippolyte Avatar answered Feb 14 '23 11:02

Casimir et Hippolyte