Replace text with preg_match_all using PHP

88 Views Asked by At

I have this string:

The product title is [title] and the price is [price] and this product link is [link]

and I have a variable called $get_product whch contain associated array.

Now, I want to replace [xxx] from the string with the $get_product[xxx] variable key. What I am doing this:

$pattern = '/\[(.*?)\]/';
preg_match_all($pattern, $optimization_prompt, $matches);

if( $matches ) {
    foreach( $matches as $key => $match ) {
        for( $i = 0; $i < count($match); $i++ ) {
            if( preg_match_all($pattern, $match[$i], $matches)  ) {
                // with bracket 
                $remove_bracket         = trim( $match[$i], '[]');
                $optimization_prompt    = str_replace( $match[$i], isset( $get_product[$remove_bracket] ) ? $get_product[$remove_bracket] : '', $optimization_prompt);
            } else {
                // Without bracket
                $remove_bracket         = trim( $match[$i], '[]');
                $optimization_prompt    = str_replace( $match[$i], '', $optimization_prompt);
            }
        }
    }
}

Its returning me:

<pre>The product  is  Infaillible Full Wear327 Cashm and the  is  10.49  and this product  is  https://www.farmaeurope.eu/infaillible-full-wear327-cashm.html</pre>

The result is okay but its removed the actual text called title, price link

4

There are 4 best solutions below

1
Destroy666 On BEST ANSWER

I don't know what you're trying to do there, but it's totally overcomplicated it seems. Here's a simple solution w/ comments:

$pattern = '/\[.*?\]/';
$get_product = ['title' => 'answer', 'price' => 666, 'link' => 'https://stackoverflow.com'];
$optimization_prompt = 'The product title is [title] and the price is [price] and this product link is [link]';
preg_match_all($pattern, $optimization_prompt, $matches);

// Cycle through full matches
foreach($matches[0] as $match) {
    // Remove the brackets for the array key
    $product_key = trim($match, '[]');
    
    // If product key available, replace it in the text
    $optimization_prompt = str_replace($match, $get_product[$product_key] ?? '', $optimization_prompt);
}

// Result: The product title is answer and the price is 666 and this product link is https://stackoverflow.com
echo $optimization_prompt;
0
Luuk On

Adding some debug lines should help:

<?php

$optimization_prompt = 'The product title is [title] and the price is [price] and this product link is [link]';
$get_product = [ "title"=>"TITLE", "price"=>"PRICE", "link"=>"LINK"];

$pattern = '/\[(.*?)\]/';
preg_match_all($pattern, $optimization_prompt, $matches);

if( $matches ) {
    foreach( $matches as $key => $match ) {
        for( $i = 0; $i < count($match); $i++ ) {
            if( preg_match_all($pattern, $match[$i], $matches)  ) {
                // with bracket 
                $remove_bracket         = trim( $match[$i], '[]');
                print "WITH Replace -$match[$i]-:". (isset( $get_product[$remove_bracket] ) ? $get_product[$remove_bracket] : '').":" .PHP_EOL;
                $optimization_prompt    = str_replace( $match[$i], isset( $get_product[$remove_bracket] ) ? $get_product[$remove_bracket] : '', $optimization_prompt);
            } else {
                // Without bracket
                $remove_bracket         = trim( $match[$i], '[]');
                print "WITHOUT Replace -$match[$i]-: ". '' .":".PHP_EOL;
                $optimization_prompt    = str_replace( $match[$i], '', $optimization_prompt);
            }
        }
    }
}

print $optimization_prompt;

output:

WITH Replace -[title]-:TITLE:
WITH Replace -[price]-:PRICE:
WITH Replace -[link]-:LINK:
WITHOUT Replace -title-: :
WITHOUT Replace -price-: :
WITHOUT Replace -link-: :
The product  is TITLE and the  is PRICE and this product  is LINK

Here: WITHOUT Replace -title-: : means that the text between - is replaced by the text between :, effectively removing the text title.

0
RiggsFolly On

If you look at the result of your first preg_match_all() you will see you have all you need in the $matches array

The $matches array

Array
(
    [0] => Array
        (
            [0] => [title]
            [1] => [price]
            [2] => [link]
        )

    [1] => Array
        (
            [0] => title
            [1] => price
            [2] => link
        )

)

So you can simplify the code to

$get_product = ['title' => '>This is a TITLE<', 
                'price' => '>£10000.99<', 
                'link' => '>http:stackoverflow.com<'
    ];
$optimization_prompt = 'The product title is [title] and the price is [price] and this product link is [link]';

$pattern = '/\[(.*?)\]/';

preg_match_all($pattern, $optimization_prompt, $matches);
print_r($matches);

foreach( $matches[0] as $i => $replace ) {
    $optimization_prompt = str_replace( $replace, $get_product[$matches[1][$i]], $optimization_prompt);
}

echo $optimization_prompt;

And the result is

The product title is >This is a TITLE< and the price is >£10000.99< and this product link is >http:stackoverflow.com<
0
Casimir et Hippolyte On

It isn't a job for preg_match_all but for preg_replace_callback (it's a replacement task yes or not?).

$get_product = ['title' => 'theTitle', 'price' => 45, 'link' => 'https://thelink.com'];

$result = preg_replace_callback(
    '~\[([^][]+)]~',
    fn($m) => $get_product[$m[1]] ?? $m[0],
    $optimization_prompt
);

demo

The pattern uses a capture group (capture group 1) to extract content between square brackets. The second parameter of preg_replace_callback is the callback function that tests if the captured content $m[1] exists as key in the array $get_product and returns the corresponding value or the full match $m[0].


Other way without regex at all (since you are looking for literal strings):

$get_product = ['title' => 'theTitle', 'price' => 45, 'link' => 'https://thelink.com'];

$result = str_replace(
    array_map(fn($k) => "[$k]", array_keys($get_product)),
    $get_product,
    $optimization_prompt
);

demo