Get all occurrences between closest double brackets - php

Given string $str = 'aa {{asd}} bla {{{888 999}} {555} 777 uiii {{-i {{qw{er}}';
Need get all occurrences between closest opening-closing double curly brackets.
Desirable result:
asd
888 999
qw{er
If try: preg_match_all('#\{\{(.*?)\}\}#', $str, $matches);
Current output:
asd
{888 999
-i {{qw{er
though, these occurrences aren't between closest double curly brackets.
Question is: what is appropriate pattern for this?

You can use this pattern:
\{\{(?!\{)((?:(?!\{\{).)*?)\}\}
The trick here is to use a negative lookahead like (?!\{\{) to avoid matching nested brackets.
\{\{ # match {{
(?!\{) # assert the next character isn't another {
(
(?: # as few times as necessary...
(?!\{\{). # match the next character as long as there is no {{
)*?
)
\}\} # match }}

Regex demo
Regex: (?<=\{{2})(?!\{)[\s\w\{]+(?=\}\})
(?=\}\}) Should contain double curly braces ahead
(?<=\{{2}) Should contain curly braces behind
(?!\{) should not contain curly braces one curly brace behind two matched
PHP code:
$str = 'aa {{asd}} bla {{{888 999}} {555} 777 uiii {{-i {{qw{er}}';
preg_match_all("/(?<=\{{2})(?!\{)[\s\w\{]+(?=\}\})/",$str,$matches);
print_r($matches);
Output:
Array
(
[0] => Array
(
[0] => asd
[1] => 888 999
[2] => qw{er
)
)

Related

Regex for find value between curly braces which have pipe separator

$str = ({max_w} * {max_h} * {key|value}) / {key_1|value}
I have the above formula, I want to match the value with curly braces and which has a pipe separator. Right now the issue is it's giving me the values which have not pipe separator. I am new in regex so not have much idea about that. I tried below one
preg_match_all("^\{(|.*?|)\}^",$str, PREG_PATTERN_ORDER);
It gives below output
Array
(
[0] => key|value
[1] => max_w
[2] => max_h
[3] => key_1|value
)
Expected output
Array
(
[0] => key|value
[1] => key_1|value
)
Not sure about PHP. Here's the general regex that will do this.
{([^{}]*\|[^{}]*)}
Here is the demo.
You can use
(?<={)[^}]*\|[^}]*(?=})
For the given string the two matches are shown by the pointy characters:
({max_w} * {max_h} * {key|value}) / {key_1|value}
^^^^^^^^^ ^^^^^^^^^^^
Demo
(?<={) is a positive lookbehind. Arguably, the positive lookahead (?=}) is not be needed if it is known that all braces appear in matching, non-overlapping pairs.
The pattern \{(|.*?|)\} has 2 alternations | that can be omitted as the alternatives on the left and right of it are not really useful.
That leaves \{(.*?)} where the . can match any char including a pipe char, and therefore does not make sure that it is matched in between.
You can use a pattern that does not crosses matching a curly or a pipe char to match a single pipe in between.
{\K[^{}|]*\|[^{}|]*(?=})
{ Match opening {
\K Forget what is matches until now
[^{}|]* Match any char except the listed
\| Match a | char
[^{}|]* Match any char except the listed
(?=}) Assert a closing } to the right
Regex demo | PHP demo
$str = "({max_w} * {max_h} * {key|value}) / {key_1|value}";
$pattern = "/{\K[^{}|]*\|[^{}|]*(?=})/";
preg_match_all($pattern, $str, $matches);
print_r($matches[0]);
Output
Array
(
[0] => key|value
[1] => key_1|value
)
Or using a capture group:
{([^{}|]*\|[^{}|]*)}
Regex demo

Match curly brace wrapped characters in a slash delimited string

I'm trying to match a substring which contains no curly braces or forward slashes AND is wrapped by curly braces THEN wrapped by delimiting forward slashes.
Pseudocode: /{ any string not contain "/" and "{" and "}" inside }/
My test string /a/{bb}/{d{b}}/{as}df}/b{cb}/a{sdfas/dsgf}
My failed pattern: \/\{((?!\/).)*\}\/
My failed result:
array(2)
=> array(2)
=> /{bb}/
=> /{as}df}/
)
=> array(2)
=> b
=> f
)
)
I want it to only match /{bb}/ and isolate bb.
You can try this mate
(?<=\/){[^\/{}]*?}(?=\/)
Explanation
(?<=\/) - Positive look behind. Matches /
{ - Matches {.
[^\/{}]*? - Matches everything except { and } and / zero or more time ( lazy mode ).
(?=\/) - Matches /.
You can use this too \/({[^\/{}]*?})\/
Demo
I extremely suggest you to use https://regex101.com/ website to test and debug your regex
this regex will work for you: (?<=/){([^/{}]+?)}(?=/)
To ensure that the whole substring between delimiting slashes is a solitary value wrapped in curly braces, I recommend that you check that:
the match starts with a delimiting slash or is at the start of the string and
the curly-brace-wrapped value does not contain any delimiting slashes or curly braces and
the match is immediately followed by a delimiting slash or is at the end of the string.
Lazy matching is not necessary/beneficial in the pattern because the negated character class will prevent the possibility of "over matching".
Cod: (Demo)
$string = '/a/{bb}/{d{b}}/{as}df}/b{cb}/a{sdfas/dsgf}';
var_export(
preg_match(
'~(?:^|/){([^{}/]*)}(?:/|$)~',
$string,
$out
)
? $out
: 'no match'
);
Output:
array (
0 => '/{bb}/', // the fullstring match
1 => 'bb', // capture group 1
)

RegEX not in brackets

I need to split text by pipe that is not in brackets. Here is the sample text
I {need|want|{ask|prefer}} you to {help {Jason|Maria|Santa|{Lucia|Raul}'s father}|go to school}
I have found this /\|(?![^{]*})/g
here: regex, extract string NOT between two brackets
now when i want to split this part of string by pipe
help {Jason|Maria|Santa|{Lucia|Raul}'s father}|go to school
it also selects pipes between Jason, Maria, Santa because there is an opening bracket after them. How to change regex to match only pipe if it's not in any of the brackets.
test strings:
help {Jason|Maria|Santa|{Lucia|Raul}'s father}|go to school
should return
help {Jason|Maria|Santa|{Lucia|Raul}'s father}
go to school
.
Jason|Maria|Santa|{Lucia|Raul}'s father
should return
Jason
Maria
Santa
{Lucia|Raul}'s father
You may use a SKIP-FAIL regex:
'~(\{(?:[^{}]++|(?1))*})(*SKIP)(*F)|\|~'
See the regex demo
Details
(\{(?:[^{}]++|(?1))*})(*SKIP)(*F) - match a substring that is between balanced curly braces and skip this match
(\{(?:[^{}]++|(?1))*}) - Capturing group 1 matching {, then 0+ repetitions of 1+ chars other than { and } or the whole Group 1 pattern is recursed ((?1) is a regex subroutine), and then } (balanced curly braces substring)
(*SKIP)(*F) - the PCRE verbs that make the regex engine fail the match and skip the matched text to proceed matching from the match end
| - or
\| - match a literal pipe to split with.
PHP demo:
$re = '~(\{(?:[^{}]++|(?1))*})(*SKIP)(*F)|\|~';
$str = "Jason|Maria|Santa|{Lucia|Raul}'s father";
print_r( preg_split($re, $str) );
Output:
Array
(
[0] => Jason
[1] => Maria
[2] => Santa
[3] => {Lucia|Raul}'s father
)

Regex of number inside brackets

I need to get the float number inside brackets..
I tried this '([0-9]*[.])?[0-9]+' but it returns the first number like 6 in the first example.
Also I tried this
'/\((\d+)\)/'
but it returns 0.
Please note that I need the extracted number either int or float.
Can u plz help
As you need to match bracket also, You need to add () in regular expression:
$str = 'Serving size 6 pieces (40)';
$str1 = 'Per bar (41.5)';
preg_match('#\(([0-9]*[.]?[0-9]+)\)#', $str, $matches);
print_r($matches);
preg_match('#\(([0-9]*[.]?[0-9]+)\)#', $str1, $matches);
print_r($matches);
Output:
Array
(
[0] => (40)
[1] => 40
)
Array
(
[0] => (41.5)
[1] => 41.5
)
DEMO
You could escape brackets:
$str = 'Serving size 6 pieces (41.5)';
if (preg_match('~\((\d+.?\d*)\)~', $str, $matches)) {
print_r($matches);
}
Outputs:
Array
(
[0] => (41.5)
[1] => 41.5
)
Regex:
\( # open bracket
( # capture group
\d+ # one or more numbers
.? # optional dot
\d* # optional numbers
) # end capture group
\) # close bracket
You could also use this to get only one digit after the dot:
'~\((\d+.?\d?)\)~'
You need to escape the brackets
preg_match('/\((\d+(?:\.\d+)?)\)/', $search, $matches);
explanation
\( escaped bracket to look for
( open subpattern
\d a number
+ one or more occurance of the character mentioned
( open Group
?: dont save data in a subpattern
\. escaped Point
\d a number
+ one or more occurance of the character mentioned
) close Group
? one or no occurance of the Group mentioned
) close subpattern
\) escaped closingbracket to look for
matches numbers like
1,
1.1,
11,
11.11,
111,
111.111 but NOT .1, .
https://regex101.com/r/ei7bIM/1
You could match an opening parenthesis, use \K to reset the starting point of the reported match and then match your value:
\(\K\d+(?:\.\d+)?(?=\))
That would match:
\( Match (
\K Reset the starting point of the reported match
\d+ Match one or more digits
(?: Non capturing group
\.\d+ Match a dot and one or more digits
)? Close non capturing group and make it optional
(?= Positive lookahead that asserts what follows is
\) Match )
) Close posive lookahead
Demo php

Split string into words in php

I want to split string which contains braces
e.g.
string = "some-thing_text,text in rounded brackets(word first,word second),Text in curly brackets{some-text(some one,some two),some another},Text in square brackets[some text,some another{some like this(this1,this2)}]"
and output will be :
Array
(
[0] => some-thing_text
[1] => text in rounded brackets(word first,word second)
[2] => Text in curly brackets{some-text(some one,some two),some another}
[3] => Text in square brackets[some text,some another{some like this(this1,this2)}]
)
,(?![^{]*})(?![^(]*\))(?![^\[]*\])
You can use this.See demo.
https://regex101.com/r/lR1eC9/8
You may try this,
preg_split('~(?:\[.*?\]|\(.*?\)|\{.*?\})(*SKIP)(*F)|,~', $str);
(?:\[.*?\]|\(.*?\)|\{.*?\}) matches all the bracketed blocks.
(*SKIP)(*F) makes the previous match to fail.
, Now it matches comma from the remaining string.
DEMO
preg_split('~,(?![^{]*}|[^(]*\)|[^\[]*\])~', $string)

Categories