I am matching pairs in regex. $pairs[1] will contain the part before = and $pairs[2] will contain the part after = .
When it gets to &startrow it should start skips rest and start making another pair.
$query= "link=http://abcd.com&efgh&lmkn&startrow=20"
preg_match_all('/(\w+)=([^&startrow]+)/', $query, $pairs);
The above regex stops at & but not at &startrow
Expected Output
$pairs[1][0] = link
$pairs[2][0] = http://abcd.com&efgh&lmkn
$pairs[1][1] =startrow
$pairs[2][1] =20
You don't need a regular expression for this; you need parse_str():
$ php -a
Interactive mode enabled
php > $params = null;
php > parse_str('link=http://abcd.com&efgh&lmkn&startrow=20', $params);
php > var_dump($params);
php shell code:1:
array(4) {
'link' =>
string(15) "http://abcd.com"
'efgh' =>
string(0) ""
'lmkn' =>
string(0) ""
'startrow' =>
string(2) "20"
}
Using following regex:
(\w+)=((?:(?!&startrow).)+)
You are able to catch both parts separately:
preg_match_all('~(\w+)=((?:(?!&startrow).)+)~', $str, $matches, PREG_SET_ORDER);
PHP output:
Array
(
[0] => Array
(
[0] => link=http://abcd.com&efgh&lmkn
[1] => link
[2] => http://abcd.com&efgh&lmkn
)
[1] => Array
(
[0] => startrow=20
[1] => startrow
[2] => 20
)
)
PHP live demo
I don't know why that would make sense, but assuming all you request are well formed and valid, you could do something plain and simple like this ;)
$_GET_RAW = [];
if (!empty($_SERVER['QUERY_STRING'])) {
// split query string into key value pairs
foreach (explode('&', $_SERVER['QUERY_STRING']) as $keyValueString) {
// separate key and value
list($key, $value) = explode('=', $keyValueString);
$_GET_RAW[$key] = $value;
}
}
Related
I want my php to recognize multiple strings in a string starting with the # symbol. Those shall then be converted into variables
//whole string
$string = "hello my name is #mo and their names are #tim and #tia."
//while loop now?
#mo #tim #tia shall then be converted to variables like:
$user1 = "mo";
$user2 = "tim";
$user3 = "tia";
Is there a php command you can use to collect them all in an array?
Regular expressions are a very flexible tool for pattern recognition:
<?php
$subject = "hello my name is #mo and their names are #tim and #tia.";
$pattern = '/#(\w+)/';
preg_match_all($pattern, $subject, $tokens);
var_dump($tokens);
The output is:
array(2) {
[0] =>
array(3) {
[0] =>
string(3) "#mo"
[1] =>
string(4) "#tim"
[2] =>
string(4) "#tia"
}
[1] =>
array(3) {
[0] =>
string(2) "mo"
[1] =>
string(3) "tim"
[2] =>
string(3) "tia"
}
}
So $token[1] is the array you are interested in.
Perhaps, you use a regex to match all those string starting with "#" and put it in an array?
preg_match_all("|\#(.*)[ .,]|U",
"hello my name is #mo and their names are #tim and #tia.",
$out, PREG_PATTERN_ORDER);
out now has the matched strings..
PS: Am not a PHP developer. Just tried out something using online
compiler.!
I have a string whose correct syntax is the regex ^([0-9]+[abc])+$. So examples of valid strings would be: '1a2b' or '00333b1119a555a0c'
For clarity, the string is a list of (value, letter) pairs and the order matters. I'm stuck with the input string so I can't change that. While testing for correct syntax seems easy in principle with the above regex, I'm trying to think of the most efficient way in PHP to transform a compliant string into a usable array something like this:
Input:
'00333b1119a555a0c'
Output:
array (
0 => array('num' => '00333', 'let' => 'b'),
1 => array('num' => '1119', 'let' => 'a'),
2 => array('num' => '555', 'let' => 'a'),
3 => array('num' => '0', 'let' => 'c')
)
I'm having difficulty using preg_match for this. For example this doesn't give the expected result, the intent being to greedy-match on EITHER \d+ (and save that) OR [abc] (and save that), repeated until end of string reached.
$text = '00b000b0b';
$out = array();
$x = preg_match("/^(?:(\d+|[abc]))+$/", $text, $out);
This didn't work either, the intent here being to greedy-match on \d+[abc] (and save these), repeated until end of string reached, and split them into numbers and letter afterwards.
$text = '00b000b0b';
$out = array();
$x = preg_match("/^(?:\d+[abc])+$/", $text, $out);
I'd planned to check syntax as part of the preg_match, then use the preg_match output to greedy-match the 'blocks' (or keep the delimiters if using preg_split), then if needed loop through the result 2 items at a time using for (...; i+=2) to extract value-letter in their pairs.
But I can't seem to even get that basic preg_split() or preg_match() approach to work smoothly, much less explore if there's a 'neater' or more efficient way.
Your regex needs a few matching groups
/([0-9]+?)([a-z])/i
This means match all numbers in one group, and all letters in another. Preg match all gets all matches.
The key to the regex is the non greedy flag ? which matches the shortest possible string.
match[0] is the whole match
match[1] is the first match group (the numbers)
match[2] is the second match group (the letter)
example below
<?php
$input = '00333b1119a555a0c';
$regex = '/([0-9]+?)([a-z])/i';
$out = [];
$parsed = [];
if (preg_match_all($regex, $input, $out)) {
foreach ($out[0] as $index => $value) {
$parsed[] = [
'num' => $out[1][$index],
'let' => $out[2][$index],
];
}
}
var_dump($parsed);
output
array(4) {
[0] =>
array(2) {
'num' =>
string(5) "00333"
'let' =>
string(1) "b"
}
[1] =>
array(2) {
'num' =>
string(4) "1119"
'let' =>
string(1) "a"
}
[2] =>
array(2) {
'num' =>
string(3) "555"
'let' =>
string(1) "a"
}
[3] =>
array(2) {
'num' =>
string(1) "0"
'let' =>
string(1) "c"
}
}
Simple solution with preg_match_all(with PREG_SET_ORDER flag) and array_map functions:
$input = '00333b1119a555a0c';
preg_match_all('/([0-9]+?)([a-z]+?)/i', $input, $matches, PREG_SET_ORDER);
$result = array_map(function($v) {
return ['num' => $v[1], 'let' => $v[2]];
}, $matches);
print_r($result);
The output:
Array
(
[0] => Array
(
[num] => 00333
[let] => b
)
[1] => Array
(
[num] => 1119
[let] => a
)
[2] => Array
(
[num] => 555
[let] => a
)
[3] => Array
(
[num] => 0
[let] => c
)
)
You can use:
$str = '00333b1119a555a0c';
$arr=array();
if (preg_match_all('/(\d+)(\p{L}+)/', $str, $m)) {
array_walk( $m[1], function ($v, $k) use(&$arr, $m ) {
$arr[] = [ 'num'=>$v, 'let'=>$m[2][$k] ]; });
}
print_r($arr);
Output:
Array
(
[0] => Array
(
[num] => 00333
[let] => b
)
[1] => Array
(
[num] => 1119
[let] => a
)
[2] => Array
(
[num] => 555
[let] => a
)
[3] => Array
(
[num] => 0
[let] => c
)
)
All of the above work. But they didn't seem to have the elegance I wanted - they needed to loop, use array mapping, or (for preg_match_all()) they needed another almost identical regex as well, just to verify the string matched the regex.
I eventually found that preg_match_all() combined with named captures solved it for me. I hadn't used named captures for that purpose before and it looks powerful.
I also added an optional extra step to simplify the output if dups aren't expected (which wasn't in the question but may help someone).
$input = '00333b1119a555a0c';
preg_match_all("/(?P<num>\d+)(?P<let>[dhm])/", $input, $raw_matches, PREG_SET_ORDER);
print_r($raw_matches);
// if dups not expected this is also worth doing
$matches = array_column($raw_matches, 'num', 'let');
print_r($matches);
More complete version with input+duplicate checking
$input = '00333b1119a555a0c';
if (!preg_match("/^(\d+[abc])+$/",$input)) {
// OPTIONAL: detected $input incorrectly formatted
}
preg_match_all("/(?P<num>\d+)(?P<let>[dhm])/", $input, $raw_matches, PREG_SET_ORDER);
$matches = array_column($raw_matches, 'num', 'let');
if (count($matches) != count($raw_matches)) {
// OPTIONAL: detected duplicate letters in $input
}
print_r($matches);
Explanation:
This uses preg_match_all() as suggested by #RomanPerekhrest and #exussum to break out the individual groups and split the numbers and letters. I used named groups so that the resulting array of $raw_matches is created with the correct names already.
But if dups arent expected, then I used an extra step with array_column(), which directly extracts data from a nested array of entries and creates a desired flat array, without any need for loops, mapping, walking, or assigning item by item: from
(group1 => (num1, let1), group2 => (num2, let2), ... )
to the "flat" array:
(let1 => num1, let2 => num2, ... )
If named regex matches feels too advanced then they can be ignored - the matches will be given numbers anyway and this will work just as well, you would have to manually assign letters and it's just harder to follow.
preg_match_all("/(\d+)([dhm])/", $input, $raw_matches, PREG_SET_ORDER);
$matches = array_column($raw_matches, 1, 2);
If you need to check for duplicated letters (which wasn't in the question but could be useful), here's how: If the original matches contained >1 entry for any letter then when array_column() is used this letter becomes a key for the new array, and duplicate keys can't exist. Only one entry for each letter gets kept. So we just test whether the number of matches originally found, is the same as the number of matches in the final array after array_coulmn. If not, there were duplicates.
I have array with login data, where I need to remove various, user defined strings, for example, my array looks like:
Array ( [0] => Date: 16/03/2015 20:39 [1] => IP Address: 93.136.99.89 [2]
What I want to do is remove "Date:" from first array element and "IP Address" from second array element.
Now I am using str_replace:
$lastlogindate = str_replace('Date:', 'Datum:', $lastlogin[0]);
But is there more elegant way of do this, and maybe, find defined occurance, and then wrapp it with tag, for every defined occurance in string in array element?
You can also still use str_replace(), but pass array arguments to it:
$lastlogindate = str_replace(array('Date: ', 'IP Address: '), '', $lastlogin);
For input array:
$lastlogin = ['Date: 16/03/2015 20:39', 'IP Address: 93.136.99.89'];
It returns you:
Array ( [0] => 16/03/2015 20:39 [1] => 93.136.99.89 )
You can also use regex to replace like this
preg_replace("/(.*?: )(.*)/", "$2", $input); by iterating over your array and replacing each value.
$input = array( 0 => 'Date: 16/03/2015 20:39', 1 => 'IP Address: 93.136.99.89' );
$array_output = array();
foreach ($input as $key => $value){
array_push($array_output, preg_replace("/(.*?: )(.*)/", "$2", $value));
}
var_dump($array_output);
// this is the output
array(2) {
[0]=>
string(16) "16/03/2015 20:39"
[1]=>
string(12) "93.136.99.89"
}
Hope this helps
I'm very new to php and I've been spending quite some type understanding how to pass arguments from Python to php and conversely.
I now know how to pass single variables, but I am still stuck and can't seem to find an answer to this one:
Php calls a Python script (that part works) that returns a list of strings. I'd like to process this list in php.
When I try:
print mylist
in myscript.py, and then :
$result = exec('python myscript.py')
it looks like php understands $result as a single string (which I agree makes sense).
I understand that maybe json can help or that I somehow need to use a dictionary instead of a list in python. However I can't figure out how exactly.
If anyone can help, it will be much appreciated! Thanks!
For instance:
myscript.py
import json
D = {'foo':1, 'baz': 2}
print json.dumps(D)
myscript.php
<?php
$result = json_decode(exec('python myscript.py'), true);
echo $result['foo'];
You're using stdin / stdout to transfer the data between the programs, that means you'll have to encode your structure somehow in order to let your receiving program parse the elements.
The simplest thing would be to have python output something like a comma separated list
Adam,Barry,Cain
and use
$result = explode(exec('python myscript.py'));
on the php side to turn your string data back into an array.
If the data is unpredictable (might contain commas) or more structured (more than just a simple list) then you should go for something like json as suggested by Krab.
Apparently your question was misleading. Was redirected here thinking this a solution for converting python lists to php array.
Posting a naive solution for ones wanting to convert lists to php array.
// Sample python list
$data = '[["1","2","3","4"],["11","12","13","14"],["21","22","23","24"]]';
// Removing the outer list brackets
$data = substr($data,1,-1);
$myArr = array();
// Will get a 3 dimensional array, one dimension for each list
$myArr =explode('],', $data);
// Removing last list bracket for the last dimension
if(count($myArr)>1)
$myArr[count($myArr)-1] = substr($myArr[count($myArr)-1],0,-1);
// Removing first last bracket for each dimenion and breaking it down further
foreach ($myArr as $key => $value) {
$value = substr($value,1);
$myArr[$key] = array();
$myArr[$key] = explode(',',$value);
}
//Output
Array
(
[0] => Array
(
[0] => "1"
[1] => "2"
[2] => "3"
[3] => "4"
)
[1] => Array
(
[0] => "11"
[1] => "12"
[2] => "13"
[3] => "14"
)
[2] => Array
(
[0] => "21"
[1] => "22"
[2] => "23"
[3] => "24"
)
)
$str = "[u'element1', u'element2', 'element3']";
$str = str_replace( array("u'", "[", "]"), array("'", ""), $str );
$strToPHPArray = str_getcsv($str, ",", "'");
print_r( $strToPHPArray );
Outputs
Array
(
[0] => element1
[1] => element2
[2] => element3
)
I have this sample string in a source:
#include_plugin:PluginName param1=value1 param2=value2#
What I want is to find all occurances of #include_plugin:*# from a source with a result of the PluginName and each paramN=valueN.
At this moment I'm fiddling with something like this (and have tried many variants): /#include_plugin:(.*\b){1}(.*\=.*){0,}#/ (using this resource). Unfortunately I can't seem to define a pattern which is giving me the result I want. Any suggestions?
Update with example:
Say I have this string in a .tpl-file. #include_plugin:BestSellers limit=5 fromCategory=123#
I want it to return an array with:
0 => BestSellers,
1 => limit=5 fromCategory=123
Or even better (if possible):
0 => BestSellers,
1 => limit=5,
2 => fromCategory=123
You can do it in 2 steps. First capture the line with a regex, then explode the parameters into an array:
$subject = '#include_plugin:PluginName param1=value1 param2=value2#';
$pattern = '/#include_plugin:([a-z]+)( .*)?#/i';
preg_match($pattern, $subject, $matches);
$pluginName = $matches[1];
$pluginParams = isset($matches[2])?explode(' ', trim($matches[2])):array();
You can use this regex:
/#include_plugin:([a-zA-Z0-9]+)(.*?)#/
The PluginName is in the first capturing group, and the parameters are in the second capturing group. Note that the parameters, if any, has a leading spaces.
It is not possible to write a regex to extract to your even better case, unless the maximum number of parameters in known.
You can do extra processing by first trimming leading and trailing spaces, then split along /\s+/.
I'm not sure of your character-set that your PluginName can contain, or the parameters/values, but in case they are limited you can use the following regex:
/#include_plugin:((?:\w+)(?:\s+[a-zA-Z0-9]+=[a-zA-Z0-9]+)*)#/
This will capture the plugin name followed by any list of alpha-numeric parameters with their values. The output can be seen with:
<?
$str = '#include_plugin:PluginName param1=value1 param2=value2#
#include_plugin:BestSellers limit=5 fromCategory=123#';
$regex = '/#include_plugin:((?:\w+)(?:\s+[a-zA-Z0-9]+=[a-zA-Z0-9]+)*)#/';
$matches = array();
preg_match_all($regex, $str, $matches);
print_r($matches);
?>
This will output:
Array
(
[0] => Array
(
[0] => #include_plugin:PluginName param1=value1 param2=value2#
[1] => #include_plugin:BestSellers limit=5 fromCategory=123#
)
[1] => Array
(
[0] => PluginName param1=value1 param2=value2
[1] => BestSellers limit=5 fromCategory=123
)
)
To get the array in the format you need, you can iterate through the results with:
$plugins = array();
foreach ($matches[1] as $match) {
$plugins[] = explode(' ', $match);
}
And now you'll have the following in $plugins:
Array
(
[0] => Array
(
[0] => PluginName
[1] => param1=value1
[2] => param2=value2
)
[1] => Array
(
[0] => BestSellers
[1] => limit=5
[2] => fromCategory=123
)
)
$string = "#include_plugin:PluginName1 param1=value1 param2=value2# #include_plugin:PluginName2#";
preg_match_all('/#include_plugin:([a-zA-Z0-9]+)\s?([^#]+)?/', $string, $matches);
var_dump($matches);
is this what you are looking for?
array(3) {
[0]=>
array(2) {
[0]=>
string(55) "#include_plugin:PluginName1 param1=value1 param2=value2"
[1]=>
string(27) "#include_plugin:PluginName2"
}
[1]=>
array(2) {
[0]=>
string(11) "PluginName1"
[1]=>
string(11) "PluginName2"
}
[2]=>
array(2) {
[0]=>
string(27) "param1=value1 param2=value2"
[1]=>
string(0) ""
}
}
This Regex will give you multiple groups, one for each plugin.
((?<=#include_plugin:)(.+))