PHP - preg_match_all Same Group, Different Pattern - php

<?php
$str = '123.456.789.987,654,321,';
// preg_match_all('((?<grp1>\d{3})\.|(?<grp2>\d{3})\,)', $str, $matches);
preg_match_all('((?<grp1>\d{3})\.|(?<grp1>\d{3})\,)', $str, $matches);
print_r($matches);
?>
Based on code above, I want to get all the string as an group array called grp1, but it always become error PHP Warning: preg_match_all(): Compilation failed: two named subpatterns have the same name at offset .... If I change one of the group name to grp2 it works well.
Is it possible to using 1 group name instead of different group name in preg_match_all?
Update
There is a reason why I cannot using something like this /(?<grp1>\d{3})[.,]/, here is an example to clear the problem:
<?php
$str = '
src="img1.png"
src="img2.jpg"
url(img3.png)
url(img4.jpg)
';
preg_match_all('/src=\"(?<img1>(\w+)(.png|.jpg))\"|url\((?<img2>(\w+)(.png|.jpg))\)/', $str, $matches);
print_r($matches);
?>
I want to take all the img1.png, img2.jpg, img3.png and img4.jpg into array group named img something like this:
[img] => Array
(
[0] => img1.png
[1] => img2.jpg
[2] => img3.png
[3] => img4.jpg
)

First of all a regex in PHP needs to be wrapped in boundaries like / or # etc.
Then your regex doesn't need to be this complex. Same can be simplified using this regex:
/(?<grp1>\d{3})[.,]/
Full Code:
$str = '123.456.789.987,654,321,';
preg_match_all('/(?<grp1>\d{3})[.,]/', $str, $matches);
print_r($matches['grp1']);
OUTPUT:
Array
(
[0] => 123
[1] => 456
[2] => 789
[3] => 987
[4] => 654
[5] => 321
)
UPDATE: As per your updated question:
$str = '
src="img1.png"
src="img2.jpg"
url(img3.png)
url(img4.jpg)
';
preg_match_all('/(?<=src="|url\()(?<img>[^")]+)/i', $str, $matches);
print_r($matches['img']);
OUTPUT:
Array
(
[0] => img1.png
[1] => img2.jpg
[2] => img3.png
[3] => img4.jpg
)

Related

Retrieving text outside square brackets in PHP

I need some way of capturing the text outside square brackets. So for example, the following string:
My [ground]name[test]Jhon[random]petor [shorts].
I m using the below preg match expression but the result could not be expected
preg_match_all("/\[[^\]]*\]/", $text, $matches);
it giving me the result which is within the square bracket.
Result :
Array (
[0] => [ground]
[1] => [test]
[2] => [random]
[3] => [shorts]
)
Expect Output:
Array (
[0] => [My]
[1] => [name]
[2] => [Jhon]
[3] => [petor]
)
Any help that would be great
You can extend the pattern adding \K to clean what is matched so far and then using an alternation to match 1 or more word characters.
\[[^][]+]\K|\w+
See a regex demo
$re = '/\[[^][]+]\K|\w+/';
$str = 'My [ground]name[test]Jhon[random]petor [shorts].';
preg_match_all($re, $str, $matches);
print_r(array_values(array_filter($matches[0])));
Output
Array
(
[0] => My
[1] => name
[2] => Jhon
[3] => petor
)

php regex mach before and after specific word

I have a string with data that looks like this:
$string = '
foo=bar
badge_name_foo=foo
bar_badge_name=bar
bar=baz
';
I want to match all *_badge_name and badge_name_* strings.
The regex im using is this:
preg_match_all('~(?:(\w+)_)?badge_name(?:_(\w+))?~', $string, $matches, PREG_SET_ORDER);
The result is:
Array
(
[0] => Array
(
[0] => badge_name_foo
[1] =>
[2] => foo
)
[1] => Array
(
[0] => bar_badge_name
[1] => bar
)
)
The *_badge_name is working fine, but on badge_name_* there is every time a empty value? Now how can i remove that with preg_match_all
Expected result should be:
Array
(
[0] => Array
(
[0] => badge_name_foo
[1] => foo
)
[1] => Array
(
[0] => bar_badge_name
[1] => bar
)
)
It seems you need to use BRANCH RESET feature:
Alternatives inside a branch reset group share the same capturing groups. The syntax is (?|regex) where (?| opens the group and regex is any regular expression. If you don't use any alternation or capturing groups inside the branch reset group, then its special function doesn't come into play. It then acts as a non-capturing group.
Use
(?|(\w+)_badge_name|badge_name_(\w+))
^^^
See the regex demo.
PHP demo:
$re = '/(?|(\w+)_badge_name|badge_name_(\w+))/';
$str = 'foo=bar
badge_name_foo=foo
bar_badge_name=bar
bar=baz';
preg_match_all($re, $str, $matches);
print_r($matches);
Result:
Array
(
[0] => Array
(
[0] => badge_name_foo
[1] => bar_badge_name
)
[1] => Array
(
[0] => foo
[1] => bar
)
)

Regex PHP only gets the first match

I have an string which looks like:
aaaaaaaa'bbbbbbbb?'cccccccccccc'ddddddddd'
I would like to get all the matches separate by ' but not the ones escaped with ?'
I managed to do it by using this expression:
(.*?)[^\\?]'
And I tested it on regexpal and seems to work properly.
When trying to apply it to my PHP code by using preg_match I only get the first match.
This is my code:
preg_match ("/(.*?)[^\\?]'/i", $content, $matches);
print_r($matches);
And the result is:
Array
(
[0] => aaaaaaaaaaaaaaaa'
[1] => aaaaaaaaaaaaaaa
)
I'm expecting to get bbbbbbbb?'cccccccccccc' and ddddddddd' as well.
What am I doing wrong? Thanks.
You can use this negative lookbehind regex in preg_match_all:
$s = "aaaaaaaa'bbbbbbbb?'cccccccccccc'ddddddddd'";
if (preg_match_all("/(.*?)(?<!\?)'/", $s , $m ))
print_r($m[1]);
OR using preg_split:
$arr = preg_split("/(?<!\?)'/", $s, -1, PREG_SPLIT_NO_EMPTY);
OUTPUT
Array
(
[0] => aaaaaaaa
[1] => bbbbbbbb?'cccccccccccc
[2] => ddddddddd
)
use preg_match_all() to get all matches instead of one
$content = "aaaaaaaa'bbbbbbbb?'cccccccccccc'ddddddddd'";
preg_match_all("/(.*?)[^\\?]'/i", $content, $matches);
print_r($matches);
result
Array (
[0] =>
Array (
[0] => aaaaaaaa'
[1] => bbbbbbbb?'cccccccccccc'
[2] => ddddddddd'
)
[1] =>
Array (
[0] => aaaaaaa
[1] => bbbbbbbb?'ccccccccccc
[2] => dddddddd
)
)
Simply You can try this
$s = "aaaaaaaa'bbbbbbbb?'cccccccccccc'ddddddddd'";
$arr = preg_split("/[^?]'/", $s, -1, PREG_SPLIT_NO_EMPTY);
Out Put Array
Array
(
[0] => aaaaaaa
[1] => bbbbbbbb?'ccccccccccc
[2] => dddddddd
)

Explode array three times

I have a string and I would like to explode with three differents patterns. The string looks like to :
country:00/00/00->link:00/00/00->link2
country2:00/00/00->link3:00/00/00->link4
I would like to get the differents parts of this two strings. The two lines are separated by a /n, the dates are separated by : and the link associated to date are separated with a ->
At the beginning I explode by the line break
$var = explode("\n", $var);
but when I tried to explode again this string, I get an error : *preg_split() expects parameter 2 to be string, array given*
How can I get the different parts ?
Thanks in advance.
Ideone link
Instead of using preg_split, consider using preg_match. You can write it as one big regex.
<?php
// Implicit newline. Adding \n would make an empty spot in the array
$str = "country:00/00/00->link:00/00/00->link2
country2:00/00/00->link3:00/00/00->link4";
$arr = split("\n", $str);
for ($i = 0; $i < count($arr); $i++) {
preg_match("/^(\w+)\:(\d\d\/\d\d\/\d\d)->(\w+)\:(\d\d\/\d\d\/\d\d)->(\w+)/", $arr[$i], $matches);
print_r($matches);
}
?>
Output:
Array
(
[0] => country:00/00/00->link:00/00/00->link2
[1] => country
[2] => 00/00/00
[3] => link
[4] => 00/00/00
[5] => link2
)
Array
(
[0] => country2:00/00/00->link3:00/00/00->link4
[1] => country2
[2] => 00/00/00
[3] => link3
[4] => 00/00/00
[5] => link4
)
EDIT
In your comment, you're posting dates with 4 digits, whereas in your question, they only had 2 digits.
Therefore you need to change the regex to:
/^(\w+)\:(\d\d\/\d\d\/\d\d\d\d)->(\w+)\:(\d\d\/\d\d\/\d\d\d\d)->(\w+)/
How about using preg_match_all:
<?php
$data =<<<ENDDATA
country:00/00/00->link:00/00/00->link2
country2:00/00/00->link3:00/00/00->link4
ENDDATA;
preg_match_all('#(\d{2}/\d{2}/\d{2})->(.[^:\n]+)#', $data, $matches);
print_r($matches);
Gives the following result:
Array
(
[0] => Array
(
[0] => 00/00/00->link
[1] => 00/00/00->link2
[2] => 00/00/00->link3
[3] => 00/00/00->link4
)
[1] => Array
(
[0] => 00/00/00
[1] => 00/00/00
[2] => 00/00/00
[3] => 00/00/00
)
[2] => Array
(
[0] => link
[1] => link2
[2] => link3
[3] => link4
)
)
your problem is that after using explode first time, it is turning into an array and explode function connat explode an array. You need to use a loop probablr for loop that targets array elemets then use explode function on those elements and you will have it.
See example Below:
<?php
$val="abc~~~def~~~ghi####jkl~~~mno~~~pqr###stu~~~vwx~~~yz1";
$val=explode("####", $val);
//result will be
$valWillBe=array(3) {
[0]=>'abc~~~def~~~ghi',
[1]=>'jkl~~~mno~~~pqr',
[2]=>'stu~~~vwx~~~yz1'
}
//if you want to explode again you use a loop
for($r=0; $r<sizeof($val); $r++){
$val[$r]=explode("~~~", $val[$r]);
}
//now you have your string exploded all in places.
?>

PHP regex preg_split - split by largest group only

I have the following regex
((\$|(\\\[)).*?(\$|(\\\])))
which should capture everything between $$ and \[\] and I tested it on http://gskinner.com/RegExr/ and it's working.
PHP variant is (doubled backslashes)
((\$|(\\\\\[)).*?(\$|(\\\\\])))
and I would like to split my text based on that regex. How can I tell that it uses just the first (and largest group) and not these small ones?
preg_split('/((\$|(\\\\\[)).*?(\$|(\\\\\])))/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
So for text This is my $test$ for something. I should get an array
[0] => This is my
[1] => $test$
[2] => for something.
But I get
[0] => This is my
[1] => $test$
[2] => $
[3] =>
[4] => $
[5] => for something.
You would need something like this:
$text = 'This is my $test$ for \[something\] new!';
print_r(preg_split('/(\$.*?\$|\\\\\[.*?\\\\\])/', $text, -1, PREG_SPLIT_DELIM_CAPTURE));
Output:
Array
(
[0] => This is my
[1] => $test$
[2] => for
[3] => \[something\]
[4] => new!
)
IMHO, your regex is (probably) wrong. It would fail for texts like Hello $there\]. If you need to capture texts between two $s and a pair of \[ and \], then you need the regexp like:
<-------------> Match text between \[ and \]
/(\$.*?\$|\\\\\[.*?\\\\\])/
<-----> Match text between dollars

Categories