Preg_match a string containing key value pattern - php

I need a regular expression for PHP's preg_match that can process something along the lines of:
variable1=true&variable2=1,2,3&variable3="test"&variable4!=true&variable5!=4,5,6&variable!="test"
I would change to just something like json but this wouldn't support the backwards compatibility I need, any suggestions, the closest I got was something like:
/((\w+)(=|!=)("\w+"|true|false|\d+)*)/
Which is partly successful, any help would be great.

Using string functions
$string = 'variable1=true&variable2=1,2,3&variable3="test"&variable4!=true&variable5!=4,5,6&variable!="test"';
$pairs = explode('&', $string);
foreach ($pairs as $pair) {
if (strstr($pair, '!=')) {
list($key, $value) = explode('!=', $pair);
} else {
list($key, $value) = explode('=', $pair);
}
$values[$key] = $value;
}
View the output on codepad
This code first splits the string using &, so into key-value pairs.
After that, it loops through each pair and tries to split it again, first using !=, and if that fails, using =.
Using regex
preg_match_all('/((\w+)(=|!=)("\w+"|true|false|[\d\,]+)*)/', $string, $matches);
I added the brackets [...] around \d and an escaped comma \,.

There is actually a built-in function parse_str, exactly for this purpose.
There is no need for regex here.

Related

How do I get an Expression out of a string in PHP?

Please, how do I extract an expression from a string?
For example, I have this string below:
RECEIPT_NO=5001809252729&PAYMENT_CODE=500858991537884262034&MERCHANT_CODE=0350000AFT&TRANS_AMOUNT=42990.0&TRANS_DATE=2018/09/25 14:04:28&TRANS_DESCR=Victor-300%20Level%20-001-
What I want to do is compare the value inputted by a user with the value in bold
How do I go about it using PHP?
I had tried using str_split('/[&]/', $string);, but I wasnt getting what I wanted. Please help.
Thanks.
You have a string in standard HTTP "query string" format (percent-encoded and &-separated key=value pairs). The easiest way to handle it is using PHP's built-in parse_str() function:
$items = [];
parse_str($string, $items);
echo $items["PAYMENT_CODE"];
If this function did not exist, you could reimplement it;
$items = [];
foreach (explode("&", $string) as $item) {
list($key, $val) = explode("=", $item, 2);
$items[urldecode($key)] = urldecode($val);
}
You must use explode() in PHP;
In your case like this :
$str = 'RECEIPT_NO=5001809252729&PAYMENT_CODE=500858991537884262034&MERCHANT_CODE=0350000AFT&TRANS_AMOUNT=42990.0&TRANS_DATE=2018/09/25 14:04:28&TRANS_DESCR=Victor-300%20Level%20-001-';
$arrayOfVars = explode('&',$str);
look at explode() documentation in PHP.net

regular expression word preceded by char

I want to grab a specific string only if a certain word is followed by a = sign.
Also, I want to get all the info after that = sign until a / is reached or the string ends.
Let's take into example:
somestring.bla/test=123/ohboy/item/item=capture
I want to get item=capture but not item alone.
I was thinking about using lookaheads but I'm not sure it this is the way to go. I appreciate any help as I'm trying to grasp more and more about regular expressions.
[^/=]*=[^/]*
will give you all the pairs that match your requirements.
So from your example it should return:
test=123
item=capture
Refiddle Demo
If you want to capture item=capture, it is straightforward:
/item=[^\/]*/
If you want to also extract the value,
/item=([^\/]*)/
If you only want to match the value, then you need to use a look-behind.
/(?<=item=)[^\/]*/
EDIT: too many errors due to insomnia. Also, screw PHP and its failure to disregard separators in a character group as separators.
Here is a function I wrote some time ago. I modified it a little, and added the $keys argument so that you can specify valid keys:
function getKeyValue($string, Array $keys = null) {
$keys = (empty($keys) ? '[\w\d]+' : implode('|', $keys));
$pattern = "/(?<=\/|$)(?P<key>{$keys})\s*=\s*(?P<value>.+?)(?=\/|$)/";
preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);
foreach ($matches as & $match) {
foreach ($match as $key => $value) {
if (is_int($key)) {
unset($match[$key]);
}
}
}
return $matches ?: FALSE;
}
Just trow in the string and valid keys:
$string = 'somestring.bla/test=123/ohboy/item/item=capture';
$keys = array('test', 'item');
$keyValuePairs = getKeyValue($string, $keys);
var_dump($keyValuePairs);

get the results of curl in variables

i got a piece of code that so far returns me data like this when i use print $result;
ssl_card_number=41**********1111
ssl_exp_date=0213
ssl_amount=132.86
ssl_salestax=0.00
ssl_invoice_number=5351353519500
ssl_result=0
ssl_result_message=APPROVED
ssl_txn_id=00000000-0000-0000-0000-00000000000
ssl_approval_code=123456
ssl_cvv2_response=P
ssl_avs_response=X
ssl_account_balance=0.00
ssl_txn_time=11/21/2012 12:38:20 PM
thats from view page source.
and the page itself shows it as :
ssl_card_number=41**********1111 ssl_exp_date=0213 ssl_amount=132.86 ssl_salestax=0.00 ssl_invoice_number=8601353519473 ssl_result=0 ssl_result_message=APPROVED ssl_txn_id=00000000-0000-0000-0000-00000000000 ssl_approval_code=123456 ssl_cvv2_response=P ssl_avs_response=X ssl_account_balance=0.00 ssl_txn_time=11/21/2012 12:37:54 PM
i need to be able to handle each of the "keys" in a better way and dont know how to explode them maybe ?
One possible approach:
parse_str(preg_replace('#\s+(?=\w+=)#', '&', $result), $array);
var_dump($array);
Explanation: preg_replace will turn all the whitespace before the param names into '&' symbol - making this string similar to the regular GET request url. Then parse_str (the function created specifically for parsing such urls) will, well, parse this string (sent as the first param), making an associative array of it.
In fact, you don't even have to use preg_replace here, if each param=value string begins from a new line; str_replace("\n", '&') should do the trick.
An alternative approach:
$pairs = preg_split('#\s+(?=\w+=)#', $x);
foreach ($pairs as $pair) {
list ($key, $value) = explode('=', $pair, 2);
$array[$key] = $value;
}
Here you first create an array of 'key-value pair' strings, then split each element by =: the first part would be the key, the second - the value.
You can use the regular expression reported by #raina77ow or you could use explodes (riskier):
<?php
$tmps = explode("\n",$result); //this gives you each line separate
foreach($tmps as $tmp){
list($key,$value) = explode('=',$tmp,2);
echo $key.' has value '.$value."\n";
//you can even create vars with the "key" if you are sure that they key is a "clean" string:
$$key=$value;
//or put everything into an array - similar to the regexp
$result_array[$key] = $value;
}
?>

array matching and display in php

i am using PHP scripts to implement this...
$keyword=array('local news','art','local','world','tech','entertainment','news','tech','top stories','in the news','front page','bbc news','week in a glance','week in pictures','top stories');
//$keyword has predefined array of strings
$all_meta_tags=get_meta_tags("http://abcnews.go.com/");
$array=$all_meta_tags['keywords'];//store 'keyword' attribute values in $keyword_meta
Now i have to match contents of $array with $keyword.....the results should give me matched items of $array which are present in $keyword
any help plz...?
can array matching/intersection be done case insensitively??
i mean if
$keyword=array('local news');
$array = 'Local News, International News';
var_dump(array_intersect(preg_split('/,\s*/', $array), $keyword));
then it won't match 'Local News'...can you tel me hw to do it if it is possible??
$inBoth = array_intersect(preg_split('/,\s*/', $array), $keyword);
CodePad.
get_meta_tags() just returns the keywords as a string, so we need to split it into an array. We take into account people adding spaces, newlines or tabs after the ,.
You could also skip the regex, and explode on , and then use array_map('trim', $array).
Without doing this, you run the risk of "art" and " art" not matching.
Update
can array matching be done case insensitively?
If you don't mind the resulting arrays being lowercase, you could use array_map('strtolower', $array) on both arrays before using array_intersect().
Otherwise, this will do it...
$metaKeywords = preg_split('/,\s*/', $array);
$matches = array();
foreach($keyword as $keyword) {
foreach($metaKeywords as $value) {
if (strtolower($value) == strtolower($keyword)) {
$matches[] = $keyword;
}
}
}
$matches will have keywords in both arrays case insensitively.
If you have multibyte strings, use mb_strtolower() or equivalent.
You need to use array_intersect()
http://php.net/manual/en/function.array-intersect.php

preg_match: equal sign in pattern

I have this query:
list[One]=1&list[Two]=2&list[Apple]=fruit
this is the regex I use to return the values in the brackets and after the equal sign
preg_match_all('/(?<query>list\[(?<pagename>.*?)\]\=(?<parent>.*?))/',$source,$array);
returns:
One=
Two=
Apple=
Values that come after the equal sign are missing. Where's my mistake?
By the way, this query is generated with jquery's serialize(). Is there a better method to parse the values?
As I made in a comment, you may want to look in to parse_str
However, if you change the final .*? to something like [^&]* then you'll probbaly have better luck (assuming this is a GET query string (or some facsimile) as & will have to be escaped from the sequence with %26)
(?<parent>.*?) matches an empty string, so the result ist 'correct'. Try (?<parent>[^&]+) instead:
preg_match_all('/(?<query>list\[(?<pagename>.*?)\]\=(?<parent>[^&]+))/',$source,$array);
Because you use the non-greedy ? for <parent>, it's not grabbing the values. Try the other answers or if you can count on the format list[<name>]=<value> then you can avoid using regex altogether.
$query = 'list[One]=1&list[Two]=2&list[Apple]=fruit';
$pieces = explode('&', $query);
$matches = array();
foreach ($pieces as $piece) {
list($key, $value) = explode('=', $piece);
$matches[substr($key, 5, -1)] = $value;
}

Categories