FlamingMoe
FlamingMoe

Reputation: 2992

regular expression in php: take the shortest match

I'm trying to do a PHP regular expression but i can't find the right way ...

Imagine I have this string: "hello, my {{name is Peter}} and {{I want to eat chocolate}}"

I want to take the parts between {{ and }}

But if I use preg_match("/\{\{(.*)?\}\}/", $string)

it returns me jut one string "{{name is Peter}} and {{I want to eat chocolate}}"

How can I tell to take the first coincidences of }} ?

Thank you

Upvotes: 10

Views: 9151

Answers (5)

Kyle Coots
Kyle Coots

Reputation: 2131

This worked for me.

$subject = 'Hello {{name}}, here is an email {{email}} and phone # {{phone}}';
$replace = array(
    '{{name}}' => 'Bob',
    '{{email}}' => '[email protected]',
    '{{phone}}' => '5155554455'
);

$output = preg_replace_callback('{{{?(#[a-z]+ )?[a-z]+.[a-z]*}?}}', function($match) use ($replace) {
    if(isset($replace[$match[0]])){
        return ($replace[$match[0]]);
    } else {
        return($match[0]);
    } 
}, $subject);

var_dump($output);

Upvotes: 0

KingCrunch
KingCrunch

Reputation: 132051

The PCRE functions a greedy by default. That means, that the engine always tries to match as much characters as possible. The solution is simple: Just tell him to act non-greedy with the U modifier

/{{(.+)}}/U

http://php.net/reference.pcre.pattern.modifiers

Upvotes: 8

morja
morja

Reputation: 8560

EDITED

As non-greedy matching seems to be faster than negated one (see here), I change my answer too. Thought it was the other way round...

preg_match("/\{\{(.*?)\}\}/", $string)

You might want to use preg_match_all to get all matches

Upvotes: 0

Piskvor left the building
Piskvor left the building

Reputation: 92792

You want "ungreedy matching": preg_match("/{{(.*?)?}}/", $string).

Note the first question mark - a regex, by default, is "greedy": given multiple ways to match, it matches as much text as it possibly can. Adding the question mark will make it ungreedy, so if there are multiple ways to match, it will match as few characters as it possibly can.

Upvotes: 2

Jens
Jens

Reputation: 25593

Use

"/{{(.*?)}}/"

The expression ".*" is greedy, taking as many characters as possible. If you use ".*?" is takes as little characters as possible, that is it stops at the first set of closing brackets.

Upvotes: 31

Related Questions