2

I need help extracing all the sub string between curly brackets that are found inside a specific string.

I found some solutions in javascript but I need it for PHP.

$string = "www.example.com/?foo={foo}&test={test}";
$subStrings = HELPME($string);
print_r($subStrings);

The result should be:

array( [0] => foo, [1] => test )

I tried playing with preg_match but I got confused.

I'd appreciate if whoever manage to get it to work with preg_match, explain also what is the logic behind it.

2
  • What is the context that you are doing this in? Commented Jun 25, 2014 at 14:07
  • Are you trying to edit a template that will be parsed? Otherwise, when would you run into a url like that? Commented Jun 25, 2014 at 14:13

7 Answers 7

6

You could use this regex to capture the strings between {}

\{([^}]*)\}

Explanation:

  • \{ Matches a literal {
  • ([^}]*) Capture all the characters not of } zero or more times. So it would capture upto the next } symbol.
  • \} Matches a literal }

Your code would be,

<?php
$regex = '~\{([^}]*)\}~'; 
$string = "www.example.com/?foo={foo}&test={test}";
preg_match_all($regex, $string, $matches);
var_dump($matches[1]);
?>

Output:

array(2) {
  [0]=>
  string(3) "foo"
  [1]=>
  string(4) "test"
}

DEMO

Sign up to request clarification or add additional context in comments.

1 Comment

So many answers, yet this was the most informative and helpful. Marked. And thanks.
4

Regex Pattern: \{(\w+)\}

Get all the matches that is captured by parenthesis (). The pattern says anything that is enclosed by {...} are captured.

Sample code:

$regex = '/\{(\w{1,})\}/';
$testString = ''; // Fill this in
preg_match_all($regex, $testString, $matches);
// the $matches variable contains the list of matches

Here is demo on debuggex


If you want to capture any type of character inside the {...} then try below regex pattern.

Regex : \{(.*?)\}

Sample code:

$regex = '/\{(.{0,}?)\}/';
$testString = ''; // Fill this in
preg_match_all($regex, $testString, $matches);
// the $matches variable contains the list of matches

Here is demo on debuggex

7 Comments

This debuggex is awsome! Thanks for your help.
You don't need to use double backslashes in PHP. (as an aside comment, in the present case you don't need backslahes at all)
@CasimiretHippolyte I don't have any idea about PHP and the code is copied from debuggex and it works. Let me update my post.
If you want, you can try something like regex101.com that produces a more PHP compliant code. (however using double backslashes is not a problem, the code works, it is only useless)
The pattern is correct, to make a global search you only need to use preg_match_all instead of preg_match
|
2
<?php
$string = "www.example.com/?foo={foo}&test={test}";
$found = preg_match('/\{([^}]*)\}/',$string, $subStrings);
if($found){
   print_r($subStrings);
}else{
    echo 'NOPE !!';
}

DEMO HERE

Comments

1

Function parse_url, which parses a URL and return its components. Including the query string.

2 Comments

It isn't a bad idea, but it covers only the first step (extracting the values). However after using parse_url you must determine for each value if it begins and ends with curly brackets and you must remove them to obtain the result.
you can use this solution : $query= $_SERVER['QUERY_STRING']; parse_str($query,$out); var_dump($out);
0

Try This:

preg_match_all("/\{.*?\}/", $string, $subStrings);
var_dump($subStrings[0]);

Good Luck!

Comments

0

You can use the expression (?<=\{).*?(?=\}) to match any string of text enclosed in {}.

$string = "www.example.com/?foo={foo}&test={test}";
preg_match_all("/(?<=\{).*?(?=\})/",$string,$matches);
print_r($matches[0]);

Regex explained:

(?<=\{) is a positive lookbehind, asserting that the line of text is preceeded by a {. Similarly (?=\}) is a positive lookahead asserting that it is followed by a }. .* matches 0 or more characters of any type. And the ? in .*? makes it match the least possible amount of characters. (Meaning it matches foo in {foo} and {bar} as opposed to foo} and {bar.

$matches[0] contains an array of all the matched strings.

Comments

0

I see answers here using regular expressions with capture groups, lookarounds, and lazy quantifiers. All of these techniques will slow down the pattern -- granted, the performance is very unlikely to be noticeable in the majority of use cases. Because we are meant to offer solutions that are suitable to more scenarios than just the posted question, I'll offer a few solutions that deliver the expected result and explain the differences using the OP's www.example.com/?foo={foo}&test={test} string assigned to $url. I have prepared a php DEMO of the techniques to follow. For information about the function calls, please follow the links to the php manual. For an in depth breakdown of the regex patterns, I recommend using regex101.com -- a free online tool that allows you to test patterns against strings, see the results as both highlighted text and a grouped list, and provides a technique breakdown character-by-character of how the regex engine is interpreting your pattern.


#1 Because your input string is a url, a non-regex technique is appropriate because php has native functions to parse it: parse_url() with parse_str(). Unfortunately, your requirements go beyond extracting the query string's values, you also wish to re-index the array and remove the curly braces from the values.

parse_str(parse_url($url, PHP_URL_QUERY), $assocArray);
$values = array_map(function($v) {return trim($v, '{}');}, array_values($assocArray));
var_export($values);

While this approach is deliberate and makes fair use of native functions that were built for these jobs, it ends up making longer, more convoluted code which is somewhat unpleasant in terms of readability. Nonetheless, it provides the desired output array and should be considered as a viable process.


#2 preg_match_all() is a super brief and highly efficient technique to extract the values. One draw back with using regular expressions is that the regex engine is completely "unaware" of any special meanings that a formatted input string may have. In this case, I don't see any negative impacts, but when hiccups do arise, often the solution is to use a parser that is "format/data-type aware".

var_export(preg_match_all('~\{\K[^}]*~', $url, $matches) ? $matches[0] : []);

Notice that my pattern does not need capture groups or lookarounds; nor does my answer suffer from the use of a lazy quantifier. \K is used to "restart the fullstring match" (in other words, forget any matched characters upto that point). All of these features will mean that the regex engine can traverse the string with peak efficiency. If there is a downsides to using the function they are:

  • that a multi-dimensional array is generated while you only want a one-dimensional array
  • that the function creates a reference variable instead of returning the results

#3 preg_split() most closely aligns with the plain-English intent of your task AND it provides the exact output as its return value.

var_export(preg_split('~(?:(?:^|})[^{]*{)|}[^{]*$~', $url, 0, PREG_SPLIT_NO_EMPTY));

My pattern, while admittedly unsavoury to the novice regex pattern designer AND slightly less efficient because it is making "branched" matches (|), basically says: "Split the string at the following delimiters:

  • from the start of the string or from a }, including all non-{ characters, then the first encountered { (this is the end of the delimiter).
  • from the lasts }, including all non-{ characters until the end of the string."

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.