How to get the matched substring in preg_replace? - php

I remove the first occurrence of a html tag in a string with preg_replace as
$html = preg_replace('#<p>(.*?)</p>#i', '', $html, 1);
How can I save the deleted substring as a new string:
$deleted = '<p>...</p>';

How about using preg_replace_callback which passes the match to a user defined function.
$str = preg_replace_callback($re, function ($m) use (&$p) { $p = $m[0]; }, $str, 1);
$m any variable name for the matches array where index 0 is the full pattern match
use (&$p) any variable name for storing the match (passed by reference).
See this demo at eval.in

to get the substring you can use preg_match():
preg_match('#<p>(.*?)</p>#i', $html, $matches);
just check the $matches variable it contain what you need.
If matches is provided, then it is filled with the results of search.
$matches[0] will contain the text that matched the full pattern,
$matches1 will have the text that matched the first captured
parenthesized subpattern, and so on.
after that use preg_replace to delete the <p> tag.
but if you want only to remove the <p> tag and keep the substring just preg_replace like this :
$html = "left <p>substring</p> right";
$html = preg_replace('#</?p>#i', '', $html);
echo $html;
output :
left substring right

try using :
$result = preg_match('#<p>(.*?)</p>#i', $html);

Related

Find a pattern in a string

I am trying to detect a string inside the following pattern: [url('example')] in order to replace the value.
I thought of using a regex to get the strings inside the squared brackets and then another to get the text inside the parenthesis but I am not sure if that's the best way to do it.
//detect all strings inside brackets
preg_match_all("/\[([^\]]*)\]/", $text, $matches);
//loop though results to get the string inside the parenthesis
preg_match('#\((.*?)\)#', $match, $matches);
To match the string between the parenthesis, you might use a single pattern to get a match only:
\[url\(\K[^()]+(?=\)])
The pattern matches:
\[url\( Match [url(
\K Clear the current match buffer
[^()]+ Match 1+ chars other than ( and )
(?=\)]) Positive lookahead, assert )] to the right
See a regex demo.
For example
$re = "/\[url\(\K[^()]+(?=\)])/";
$text = "[url('example')]";
if (preg_match($re, $text, $match)) {
var_dump($match[0]);;
}
Output
string(9) "'example'"
Another option could be using a capture group. You can place the ' inside or outside the group to capture the value:
\[url\(([^()]+)\)]
See another regex demo.
For example
$re = "/\[url\(([^()]+)\)]/";
$text = "[url('example')]";
if (preg_match($re, $text, $match)) {
var_dump($match[1]);;
}
Output
string(9) "'example'"

Find next word after colon in regex

I am getting a result as a return of a laravel console command like
Some text as: 'Nerad'
Now i tried
$regex = '/(?<=\bSome text as:\s)(?:[\w-]+)/is';
preg_match_all( $regex, $d, $matches );
but its returning empty.
my guess is something is wrong with single quotes, for this i need to change the regex..
Any guess?
Note that you get no match because the ' before Nerad is not matched, nor checked with the lookbehind.
If you need to check the context, but avoid including it into the match, in PHP regex, it can be done with a \K match reset operator:
$regex = '/\bSome text as:\s*'\K[\w-]+/i';
See the regex demo
The output array structure will be cleaner than when using a capturing group and you may check for unknown width context (lookbehind patterns are fixed width in PHP PCRE regex):
$re = '/\bSome text as:\s*\'\K[\w-]+/i';
$str = "Some text as: 'Nerad'";
if (preg_match($re, $str, $match)) {
echo $match[0];
} // => Nerad
See the PHP demo
Just come from the back and capture the word in a group. The Group 1, will have the required string.
/:\s*'(\w+)'$/

Regex replace recursive with one pattern

$array[key][key]...[key]
replace to
$array['key']['key']...['key']
I managed only to add quotes to the first keyword of the array.
\$([a-zA-Z0-9]+)\[([a-zA-Z_-]+[0-9]*)\] replace to \$\1\[\'\2\3\'\]
You may use a regex that does not perform a recursive, but consecutive matching:
$re = '/(\$\w+|(?!^)\G)\[([^]]*)\]/';
$str = "\$array[key][key][key]";
$subst = "$1['$2']";
$result = preg_replace($re, $subst, $str);
echo $result;
See IDEONE demo
The regex (\$\w+|(?!^)\G)\[([^]]*)\] matches all square parenthetical substrings (capturing their contents into Group 2) (with \[([^]]*)\]) that either are right after a '$'+alphanumerics substring (due to the \$\w+ part) or that follow one another consecutively (thanks to (?!^)\G).
Shouldn't need anything fancy, just get the stuff you need then
replace in a callback.
Untested:
$new_input = preg_replace_callback('/(?i)\$[a-z]+\K(?:\[[^\[\]]*\])+/',
function( $matches ){
return preg_replace( '/(\[)|(\])/', "$1'$2", $matches[0]);
},
$input );

preg matching and replacing elements

Hi how do I do a preg match on
$string1 = "[%refund%]processed_by"
$string2 = "[%refund%]date_sent"
I want to grab the bits inside %% and then remove the [%item%] altogether. leaving just the "proccessed_by" or "date_sent" I have had a go below but come a bit stuck.
$unprocessedString = "[%refund%]date_sent"
$match = preg_match('/^\[.+\]/', $unprocessedString);
$string = preg_replace('/^\[.+\]/', $unprocessedString);
echo $match; // this should output refund
echo $string; // this should output date_sent
Your problem is with your use of the preg_match function. It returns the number of matches found. But if you pass it a variable as a third parameter, it stores the matches for the entire pattern and its subpatterns in an array.
So you can capture both of the parts you want in subpatterns with preg_match, which means you don't need preg_replace:
$unprocessedString = "[%refund%]date_sent"
preg_match('/^\[%(.+)%\](.+)/', $unprocessedString, $matches);
echo $matches[1]; // outputs 'refund'
echo $matches[2]; // outputs 'date_sent'

PHP's preg_match() returns (.*?) value only

I am struggling to get preg_match to return only the image URL and not the entire matched string. Do I need to use preg_replace after or is that getting hacky?
Possibly, would a different syntax get me what I need?
$source = file_get_contents('http://mysite.co.uk');
preg_match_all("'<div id=\"my-div\"><img src=\"(.*?)\" /></div>'", $source, $match);
echo $match[0][0];
If you use echo $match[0][0] you will have all the text.
<div id="my-div"><img src="blabla bla" /></div>
If you write $match[1][0] instead, you will get your subpattern match:
blabla bla
If you're looking for the first instance, you don't need to use preg_match_all():
$source = file_get_contents('http://mysite.co.uk');
if (preg_match('#<div id="my-div"><img src="(.*?)" /></div>#', $source, $match)) {
echo $match[1];
} else {
// no match found
}
Note that this regex will not match across multiple lines.
If you need all matches, then you were on the right track, but you were using index 0 instead of 1, so:
preg_match_all(..., $match);
foreach ($match as $m) {
echo $m[1]; // Use 1 here instead of 0; 1 is the first capture group, where 0 is the entire matched string
}
By default, preg_match_all always returns the fully matched string as the first item (using the ordering type PREG_PATTERN_ORDER).
From the documentation for PREG_PATTERN_ORDER:
Orders results so that $matches[0] is an array of full pattern
matches, $matches[1] is an array of strings matched by the first
parenthesized subpattern, and so on.
If you're looking for the value of a capturing group, check for a value at index 1 and then use the capturing group reference as a subattribute.
E.g., capturing group 1 would be: $matches[1][0]
To change this behavior you can pass a constant to as the third argument, such as PREG_SET_ORDER, which "Orders results so that $matches[0] is an array of first set of matches, $matches[1] is an array of second set of matches, and so on."

Categories