preg_match - get match with just one statement - php

I am wondering if it's possible to get a regex match in PHP by only using one statement? This question is more of a challenge to see if this is possible.
Right now you have to do something like this:
preg_match('#(\d+)$#', $subject, $match);
echo $match[1];
How do I access $match with one statement, instead of two?
I don't want to use preg_replace.
If it's possible with a closure, the better. I love fancy code.

I don't think it's possbile. the third argument $matches is always an array. From the PHP docs:
If matches is provided, then it is filled with the results of search.
$matches[0] will contain the text that matched the full pattern,
$matches[1] will have the text that matched the first captured
parenthesized subpattern, and so on.
Source: http://www.php.net/manual/en/function.preg-match.php
If you have a lot of regexes that only have one group of capturing parentheses, you could make a shortcut function for your purpose:
function preg_match_one($regex, $subject) {
if(preg_match($regex, $subject, $matches)) {
return $matches[1];
}
else {
return false;
}
}

Related

Matching substrings with PHP preg_match_all()

I'm attempting to create a lightweight BBCode parser without hardcoding regex matches for each element. My way is utilizing preg_replace_callback() to process the match in the function.
My simple yet frustrating way involves using regex to group the elements name and parse different with a switch for each function.
Here is my regex pattern:
'~\[([a-z]+)(?:=(.*))?(?: (.*))?\](.*)(?:\[/\1\])~siU'
And here is the preg_replace_callback() I've got to test.
return preg_replace_callback(
'~\[([a-z]+)(?:=(.*))?(?: (.*))?\](.*)(?:\[/\1\])~siU',
function($matches) {
var_dump($matches);
return "<".$matches[1].">".$matches[4]."</".$matches[1].">";
},
$this->raw
);
This one issue has stumped me. The regex pattern won't seem to recursively match, meaning if it matches an element, it won't match elements inside it.
Take this BBCode for instance:
[i]This is all italics along with a [b]bold[/b].[/i]
This will only match the [u], and won't match any of the elements inside of it, so it looks like
This is all italics along with a [b]bold[/b].
preg_match_all() continues to show this to be the case, and I've tried messing with greedy syntax and modes.
How can I solve this?
Thanks to #Casimir et Hippolyte for their comment, I was able to solve this using a while loop and the count parameter like they said.
The basic regex strings don't work because I would like to use values in the tags like [color=red] or [img width=""].
Here is the finalized code. It isn't perfect but it works.
$str = $this->raw;
do {
$str = preg_replace_callback(
'~\[([a-z]+)(?:=([^]\s]*))?(?: ([^[]*))?\](.*?)(?:\[/\1\])~si',
function($matches) {
return "<".$matches[1].">".$matches[4]."</".$matches[1].">";
},
$str,
-1,
$count
);
} while ($count);
return $str;

How to parse a string of function parameters with REGEX in PHP

I am trying to handle parameters like Java or PHP natively handle them, using Regex to parse variable numbers (and types) of arguments. For example, a function might be:
util.echo(5, "Hello, world!");
In this instance, I would want to separate 5 as the first argument and "Hello, world!" as the second (without quotes). What I currently do is explode by commas, but that runs into issues if the string parameters include a comma. I don't have much experience with Regex, but I think it has some way of ignoring commas that are within quotes.
The Regex from this question (",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") seems like it could work, but I'm confused on how to implement it with PHP.
To test a regular expression onto a string, you can use the preg_match() function in PHP.
See the manual
// $matches is going to output the matches
preg_match("/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/", $to_be_checked, $matches);
if($matches){
var_dump($matches);
// there was a match!
} else {
// the regular expression did not find any pattern matches
}
if you don't need to access the exact matches, just if there was at least one pattern match, you can simply do this:
if(preg_match("/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/", $to_be_checked)){
// there was a match!
} else {
// the regular expression did not find any pattern matches
}
Thank you to Zac and The fourth bird! Example solution that works, for future reference:
$parameters = 'util.echo(5, "Hello, world!");';
preg_match_all('/(?:[^\s(]+\(|\G(?!^),\s*)\K(?:"[^"]*"|[^,()]+)(?=[^()]*\);)/', $parameters, $matches);
if($matches){
var_dump($matches[0]);
} else {
echo('No matches.');
}

Regular expression return only certain values PHP

I cant remember what to use to return only a specific part of a string.
I have a string like this:-
$str = "return(me or not?)";
I want to get the word which is after (. In this example me will be my result. How can I do this?
I dont think substr is what I am looking for. as substr returns value based on the index you provided. which in this case i dont know the index, it can vary. All I know is that I want to return whatever is after "(" and before the space " ". The index positions will always be different there for i cant use substr(..).
This regular expression should do the trick. Since you didn't provide general rules but only an example it might need further changes though.
preg_match('/\((\S+)/', $input, $matches);
$matches[1] contains "me" then.
<?php
// Your input string
$string = "return(me or not?)";
// Pattern explanation:
// \( -- Match opening parentheses
// ([^\s]+) -- Capture at least one character that is not whitespace.
if (preg_match('/\(([^\s]+)/', $string, $matches) === 1)
// preg_match() returns 1 on success.
echo "Substring: {$matches[1]}";
else
// No match found, or bad regular expression.
echo 'No match found';
Result of capture group will be your result using this regex and preg_match().
$regex = '/\((\w+)/';
Check preg_match() for the working reference.

Using delimiters with preg_match

I am having difficulties to understand preg_match function.An e.g is way better
$subject="XY=abC%3Fedr%3Damp;35"
I am trying to extract
bC%3Fed
using preg_match and store it in variable
if(preg_match($pattern, $subject, $matches))
{
$string = $matches[1];
}
echo $string;
Here are the different variation that i use for $pattern
I want to use # as a delimeter
#bC(.*?)#
#bC.*?#
I just don't understand why its not working , i guess something is wrong in the $pattern.
Please don't use complicated regex and try to fix my attempt as the aim here is to understand how preg_match works and what is wrong here.
Regards
Using # as the delimiter is OK, but the regex is wrong. I guess you want:
#(bC.*?)r# // matches #bC and the following characters unless and 'r' (see comments)
A good starting point to learn the regex syntax is the PCRE manual
Example:
$subject="XY=abC%3Fedr%3Damp;35";
$pattern="#(bC.*?)r#";
preg_match($pattern, $subject, $matches);
$string = $matches[1];
echo $string; // bC%3Fed
The ? after .* switches the greediness of the pattern. By default patterns are greedy, they try to find the longest match. So you .*? means any char, any count, smallest match. Because here is nothing after that will anchor it, the smallest possible match is an empty string.

php regex - can't find the error

Just one simple, specific question:
I've got the string {var1}12345{var2}, and I want to get the variable names used.
if (preg_match("/{([a-zA-Z0-9]*)}/g", $url, $matches)) {
print_r($matches);
}
If I remove the global flag, it works, but I only get the first variable, as expected. Why isn't it working with a global flag? It works when I'm testing it with the Regex Tester
From PHP: preg_match:
preg_match() returns the number of times pattern matches. That will be either 0 times (no match) or 1 time because preg_match() will stop searching after the first match. preg_match_all() on the contrary will continue until it reaches the end of subject. preg_match() returns FALSE if an error occurred.
Use preg_match_all to fetch several matches:
if (preg_match_all("/{([a-zA-Z0-9]*)}/", $url, $matches)) {
print_r($matches[1]);
}
This should do the trick (in case you need variables in format {name}):
$url = "{var1}12345{var2}";
if (preg_match_all("/{[a-zA-Z0-9]*}/", $url, $matches)) {
print_r($matches);
}

Categories