From a text like:
category=[123,456,789], subcategories, id=579, not_in_category=[111,333]
I need a regex to get something like:
$params[category][0] = 123;
$params[category][1] = 456;
$params[category][2] = 789;
$params[subcategories] = ; // I just need to know that this exists
$params[id] = 579;
$params[not_category][0] = 111;
$params[not_category][1] = 333;
Thanks everyone for the help.
PS
As you suggested, I clarify that the structure and the number of items may change.
Basically the structure is:
key=value, key=value, key=value, ...
where value can be:
a single value (e.g. category=123 or postID=123 or mykey=myvalue, ...)
an "array" (e.g. category=[123,456,789])
a "boolean" where the TRUE value is an assumption from the fact that "key" exists in the array (e.g. subcategories)
This method should be flexible enough:
$str = 'category=[123,456,789], subcategories, id=579, not_in_category=[111,333]';
$str = preg_replace('#,([^0-9 ])#',', $1',$str); //fix for string format with no spaces (count=10,paginate,body_length=300)
preg_match_all('#(.+?)(,[^0-9]|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $param)
{
list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
{
$val = explode(',',$match[1]); //turn the comma separated numbers into an array
}
$params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
var_dump(isset($params['subcategories']));
Output:
Array
(
[category] => Array
(
[0] => 123
[1] => 456
[2] => 789
)
[subcategories] =>
[id] => 579
[not_in_category] => Array
(
[0] => 111
[1] => 333
)
)
bool(true)
Alternate (no string manipulation before process):
$str = 'count=10,paginate,body_length=300,rawr=[1,2,3]';
preg_match_all('#(.+?)(,([^0-9,])|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $k => $param)
{
list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
$key = isset($sections[3][$k-1]) ? trim($sections[3][$k-1]).$key : $key; //Fetch first character stolen by previous match
if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
{
$val = explode(',',$match[1]); //turn the comma separated numbers into an array
}
$params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
Another alternate: full re-format of string before process for safety
$str = 'count=10,paginate,body_length=300,rawr=[1, 2,3] , name = mike';
$str = preg_replace(array('#\s+#','#,([^0-9 ])#'),array('',', $1'),$str); //fix for varying string formats
preg_match_all('#(.+?)(,[^0-9]|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $param)
{
list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
{
$val = explode(',',$match[1]); //turn the comma separated numbers into an array
}
$params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
You can use JSON also, it's native in PHP : http://php.net/manual/fr/ref.json.php
It will be more easy ;)
<?php
$subject = "category=[123,456,789], subcategories, id=579, not_in_category=[111,333]";
$pattern = '/category=\[(.*?)\,(.*?)\,(.*?)\]\,\s(subcategories),\sid=(.*?)\,\snot_in_category=\[(.*?)\,(.*?)\]/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);
print_r($matches);
?>
I think this will get you the matches out... didn't actually test it but it might be a good starting point.
Then you just need to push the matches to the correct place in the array you need. Also test if the subcategories string exists with strcmp or something...
Also, notice that I assumed your subject string has that fixe dtype of structure... if it is changing often, you'll need much more than this...
$str = 'category=[123,456,789], subcategories, id=579, not_in_category=[111,333]';
$main_arr = preg_split('/(,\s)+/', $str);
$params = array();
foreach( $main_arr as $value) {
$pos = strpos($value, '=');
if($pos === false) {
$params[$value] = null;
} else {
$index_part = substr($value, 0, $pos);
$value_part = substr($value, $pos+1, strlen($value));
$match = preg_match('/\[(.*?)\]/', $value_part,$xarr);
if($match) {
$inner_arr = preg_split('/(,)+/', $xarr[1]);
foreach($inner_arr as $v) {
$params[$index_part][] = $v;
}
} else {
$params[$index_part] = $value_part;
}
}
}
print_r( $params );
Output :
Array
(
[category] => Array
(
[0] => 123
[1] => 456
[2] => 789
)
[subcategories] =>
[id] => 579
[not_in_category] => Array
(
[0] => 111
[1] => 333
)
)
Related
I have an array that looks something like this:
$array = array( [0] => FILE-F01-E1-S01.pdf
[1] => FILE-F01-E1-S02.pdf
[2] => FILE-F01-E1-S03.pdf
[3] => FILE-F01-E1-S04.pdf
[4] => FILE-F01-E1-S05.pdf
[5] => FILE-F02-E1-S01.pdf
[6] => FILE-F02-E1-S02.pdf
[7] => FILE-F02-E1-S03.pdf );
Basically, I need to look at the first file and then get all the other files that have the same beginning ('FILE-F01-E1', for example) and put them into an array. I don't need to do anything with the other ones at this point.
I've been trying to use a foreach loop finding the previous value to do this, but am not having any luck.
Like this:
$previousFile = null;
foreach($array as $file)
{
if(substr_replace($previousFile, "", -8) == substr_replace($file, "", -8))
{
$secondArray[] = $file;
}
$previousFile = $file;
}
So then $secondArray would look like this:
Array ( [0] => FILE-F01-E1-S01.pdf [1] => FILE-F01-E1-S02.pdf
[2] => FILE-F01-E1-S03.pdf [3] => FILE-F01-E1-S04.pdf
[4] => FILE-F01-E1-S05.pdf)
As my result.
Thank you!
You can use array_filter combined with strpos:
$result = array_filter($array, function($filename) {
return strpos($filename, 'FILE-F01-E1') === 0;
});
Are you sure this will be the naming format? That is crucial information to have to construct a regexp or something to check for being a substring of the following strings.
If we can assume this and that the "base" name is always at index 0 then you could do something like.
<?php
$myArr = [
'FILE-F01-E1-S01.pdf',
'FILE-F01-E1-S02.pdf',
'FILE-F01-E1-S03.pdf',
'FILE-F01-E1-S04.pdf',
'FILE-F01-E1-S05.pdf',
'FILE-F02-E1-S01.pdf',
'FILE-F02-E1-S02.pdf',
'FILE-F02-E1-S03.pdf'
];
$baseName = '';
$allSimilarNames = [];
foreach($myArr as $index => &$name) {
if($index == 0) {
$baseName = substr($name, 0, strrpos($name, '-'));
$allSimilarNames[] = $name;
}
else {
if(strpos($name, $baseName) === 0) {
$allSimilarNames[] = $name;
}
}
}
var_dump($allSimilarNames);
This will
Check at index one to get the base name to compare against
Loop all items in the array and match all items, no matter where in the array they are, that are similar according to your naming convention
So if you next time have an array that is
$myArr = [
'FILE-F02-E1-S01.pdf',
'FILE-F01-E1-S01.pdf',
'FILE-F01-E1-S02.pdf',
'FILE-F01-E1-S03.pdf',
'FILE-F01-E1-S04.pdf',
'FILE-F01-E1-S05.pdf',
'FILE-F02-E1-S02.pdf',
'FILE-F02-E1-S03.pdf'
];
this will return all the items that match FILE-F02-E1*.
You could also make a small function of it for easier use and not have to rely on the element at index 0 having to be the "base" name.
<?php
function findMatches($baseName, &$names) {
$matches = [];
$baseName = substr($baseName, 0, strrpos($baseName, '-'));
foreach($names as &$name) {
if(strpos($name, $baseName) === 0) {
$matches[] = $name;
}
}
return $matches;
}
$myArr = [
'FILE-F01-E1-S01.pdf',
'FILE-F01-E1-S02.pdf',
'FILE-F01-E1-S03.pdf',
'FILE-F01-E1-S04.pdf',
'FILE-F01-E1-S05.pdf',
'FILE-F02-E1-S01.pdf',
'FILE-F02-E1-S02.pdf',
'FILE-F02-E1-S03.pdf'
];
$allSimilarNames = findMatches('FILE-F01-E1-S01.pdf', $myArr);
var_dump($allSimilarNames);
Run a simple foreach with strpos() which looks for an occurrence of a string within a string.
$results = array();
foreach($array as $item){
if (strpos($item, 'FILE-F01-E1') === 0) {
array_push($results, $item);
}
}
You could get the first item from the array and use explode and implode to get the part from the filename without the last hyphen and the content after that.
Then use array_filter and use substr using 0 as the start position and the length of the $fileBeginning as the length to check if the string starts with FILE-F01-E1:
$array = [
'FILE-F01-E1-S01.pdf',
'FILE-F01-E1-S02.pdf',
'FILE-F01-E1-S03.pdf',
'FILE-F01-E1-S04.pdf',
'FILE-F01-E1-S05.pdf',
'FILE-F02-E1-S01.pdf',
'FILE-F02-E1-S02.pdf',
'FILE-F02-E1-S03.pdf',
"TESTFILE-F01-E1-S03.pdf"
];
$parts = explode('-', $array[0]);
array_pop($parts);
$fileBeginning = implode('-', $parts);
$secondArray = array_filter($array, function ($x) use ($fileBeginning) {
return substr($x, 0, strlen($fileBeginning)) === $fileBeginning;
});
print_r($secondArray);
Result
Array
(
[0] => FILE-F01-E1-S01.pdf
[1] => FILE-F01-E1-S02.pdf
[2] => FILE-F01-E1-S03.pdf
[3] => FILE-F01-E1-S04.pdf
[4] => FILE-F01-E1-S05.pdf
)
Demo
This is the initial string:-
NAME=Marco\nLOCATION=localhost\nSECRET=fjsdgfsjfdskffuv=\n
This is my solution although the "=" in the end of the string does not appear in the array
$env = file_get_contents(base_path() . '/.env');
// Split string on every " " and write into array
$env = preg_split('/\s+/', $env);
//create new array to push data in the foreach
$newArray = array();
foreach($env as $val){
// Split string on every "=" and write into array
$result = preg_split ('/=/', $val);
if($result[0] && $result[1])
{
$newArray[$result[0]] = $result[1];
}
}
print_r($newArray);
This is the result I get:
Array ( [Name] => Marco [LOCATION] => localhost [SECRET] => fjsdgfsjfdskffuv )
But I need :
Array ( [Name] => Marco [LOCATION] => localhost [SECRET] => fjsdgfsjfdskffuv= )
You can use the limit parameter of preg_split to make it only split the string once
http://php.net/manual/en/function.preg-split.php
you should change
$result = preg_split ('/=/', $val);
to
$result = preg_split ('/=/', $val, 2);
Hope this helps
$string = 'NAME=Marco\nLOCATION=localhost\nSECRET=fjsdgfsjfdskffuv=\n';
$strXlate = [ 'NAME=' => '"NAME":"' ,
'LOCATION=' => '","LOCATION":"',
'SECRET=' => '","SECRET":"' ,
'\n' => '' ];
$jsonified = '{'.strtr($string, $strXlate).'"}';
$array = json_decode($jsonified, true);
This is based on 1) translation using strtr(), preparing an array in json format and then using a json_decode which blows it up nicely into an array...
Same result, other approach...
You can also use parse_str to parse URL syntax-like strings to name-value pairs.
Based on your example:
$newArray = [];
$str = file_get_contents(base_path() . '/.env');
$env = explode("\n", $str);
array_walk(
$env,
function ($i) use (&$newArray) {
if (!$i) { return; }
$tmp = [];
parse_str($i, $tmp);
$newArray[] = $tmp;
}
);
var_dump($newArray);
Of course, you need to put some sanity check in the function since it can insert some strange stuff in the array like values with empty string keys, and whatnot.
I know what you're thinking. "I can answer this question so quick! It's the parse_str function!" But I've got a little twist for you.
You see, PHP converts the names of all query data into valid PHP variable names. What? Even when they're not being stored as variables? Where is that documented? It isn't.
$payload = 'data.name=value&data.other=value2';
parse_str($payload, $values);
var_export($values);
// Outputs: array('data_name' => 'value', 'data_other' => 'value2')
// Expected: array('data.name' => 'value', 'data.other' => 'value2')
How can I parse a query string without this happening?
You can avoid PHP's renaming of parameter names by parsing the query string yourself. Split the string on & and = characters, and then urldecode() each part:
<?php
$payload = 'data.name=value&data.other=value2';
$values = array();
$nv_strings = explode ('&', $payload);
foreach ($nv_strings as $s) {
$nv = explode ('=', $s, 2);
$name = urldecode ($nv[0]);
$value = (isset ($nv[1]) ? urldecode ($nv[1]) : null);
$values[$name] = $value;
}
print_r ($values);
// Array
// (
// [data.name] => value
// [data.other] => value2
// )
If your query string contains duplicate keys, the above code will overwrite the previous keys. This also can be solved:
<?php
$payload = 'key=val1&key=val2&key=val3';
$values = array();
$nv_strings = explode ('&', $payload);
foreach ($nv_strings as $s) {
$nv = explode ('=', $s, 2);
$name = urldecode ($nv[0]);
$value = (isset ($nv[1]) ? urldecode ($nv[1]) : null);
$values[] = array ($name => $value);
}
print_r ($values);
// Array
// (
// [0] => Array ([key] => val1)
// [1] => Array ([key] => val2)
// [2] => Array ([key] => val3)
// )
You may want to consolidate the duplicate keys into subarrays:
<?php
$payload = 'key1=val1&key1=val2&key2=val3';
$values = array();
$nv_strings = explode ('&', $payload);
foreach ($nv_strings as $s) {
$nv = explode ('=', $s, 2);
$name = urldecode ($nv[0]);
$value = (isset ($nv[1]) ? urldecode ($nv[1]) : null);
if (isset ($values[$name])) {
if (is_array ($values[$name])) {
$values[$name][] = $value;
} else {
$values[$name] = array ($values[$name], $value);
}
} else {
$values[$name] = $value;
}
}
print_r ($values);
// Array
// (
// [key1] => Array ([0] => val1
// [1] => val2)
// [key2] => val3
// )
You can simplify the code somewhat by always using subarrays:
<?php
$payload = 'key1=val1&key1=val2&key2=val3';
$values = array();
$nv_strings = explode ('&', $payload);
foreach ($nv_strings as $s) {
$nv = explode ('=', $s, 2);
$name = urldecode ($nv[0]);
$value = (isset ($nv[1]) ? urldecode ($nv[1]) : null);
if (isset ($values[$name])) {
$values[$name][] = $value;
} else {
$values[$name] = array ($value);
}
}
print_r ($values);
// Array
// (
// [key1] => Array ([0] => val1
// [1] => val2)
// [key2] => Array ([0] => val3)
// )
It is documented completely in PHP Documentation for the function parse_str If the output does not work for your particular use case, then you must use another function, or create your own. The key here is that this function parses the string into variables.
parse_str — Parses the string into variables
Parses str as if it were the query string passed via a URL and sets variables in the current scope.
To parse the string you provided, this would work:
$payload = 'data.name=value';
$map = array();
$vals = preg_split('/=/', $payload);
$i= 0;
while($i < count($vals)) {
$map[$vals[$i]] = $vals[++$i];
$i++;
}
var_dump($map);
I'm having a problem with this. I have a string that looks like this:
coilovers[strut_and_individual_components][complete_strut][][achse]
And i want to convert it to to array that looks like this:
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut]=> Array
(
[1] => Array
(
[achse] => some_value
)
[2] => Array
(
[achse] => some_value
)
)
)
)
is it possible?
Here is a quick implementation of a parser that will attempt to parse this string:
$input = 'coilovers[strut_and_individual_components][complete_strut][][achse]';
$output = array();
$pointer = &$output;
while( ($index = strpos( $input, '[')) !== false) {
if( $index != 0) {
$key = substr( $input, 0, $index);
$pointer[$key] = array();
$pointer = &$pointer[$key];
$input = substr( $input, $index);
continue;
}
$end_index = strpos( $input, ']');
$array_key = substr( $input, $index + 1, $end_index - 1);
$pointer[$array_key] = array();
$pointer = &$pointer[$array_key];
$input = substr( $input, $end_index + 1);
}
print_r( $output);
Essentially, we are iterating the string to find matching [ and ] tags. When we do, we take the value within the brackets as $array_key and add that into the $output array. I use another variable $pointer by reference that is pointing to the original $output array, but as the iteration goes, $pointer points to the last element added to $output.
It produces:
Array
(
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut] => Array
(
[] => Array
(
[achse] => Array
(
)
)
)
)
)
)
Note that I've left the implementation of [] (an empty array key) and setting the values in the last index (some_value) as an exercise to the user.
Well I've found an another answer for it and it looks like this:
private function format_form_data(array $form_values) {
$reformat_array = array();
$matches = array();
$result = null;
foreach($form_values as $value) {
preg_match_all("/\[(.*?)\]/", $value["name"], $matches);
$parsed_product_array = $this->parse_array($matches[1], $value["value"]);
$result = array_push($reformat_array, $parsed_product_array);
}
return $result;
}
private function parse_array(array $values, $value) {
$reformat = array();
$value_carrier_key = end($values);
foreach (array_reverse($values) as $arr) {
$set_value_carrier = array($arr => $reformat);
if($arr == $value_carrier_key) {
$set_value_carrier = array($arr => $value);
}
$reformat = empty($arr) ? array($reformat) : $set_value_carrier;
}
return $reformat;
}
where array $form_values is:
Array
(
[name] => '[coilovers][strut_and_individual_components][complete_strut][][achse]',
[value] => 'some_value'
)
No. If you evaluate the string you will get invalid PHP.
If you want to store a PHP Array as string and get it loaded back as PHP Array, have a look at serialize and unserialize functions.
Of course you can build an array from your string, but you'll have to write a parser.
The solution I propose:
function format_form_data(array $data) {
$matches = array();
$result = [];
foreach($data as $key => $value) {
preg_match_all("/\[(.*?)\]/", $key, $matches);
$matches = array_reverse($matches[1]);
$matches[] = substr( $key, 0, strpos($key, '['));;
foreach ($matches as $match) {
$value = [$match=>$value];
}
$result = array_replace_recursive($result, $value);
}
return $result;
}
I have several strings, how can I search the first value and get other values from it?
print_r or ?:
Array( [0] => Title,11,11 [1] => Would,22,22 [2] => Post,55,55 [3] => Ask,66,66 )
like:
If send for this array value Title and getting values Title,11,11
Or send Would getting values Would,22,22
Or send Post getting values Post,55,55
Or send Ask getting values Ask,66,66
How can do it?
Loop over the array with foreach and match the value with strpos.
suppose:
$arr = Array( [0] => Title,11,11 [1] => Would,22,22 [2] => Post,55,55 [3] => Ask,66,66 )
$string = 'Would';
then
//Call the function with the search value in $string and the actual array
$required_arr[$string] = search_my_array($string, $arr);
function($str , $array)
{
//Trace the complete array
for($i = 0; $i<count($array); $i++)
{
//Break the array using explode function based on ','
$arr_values[$i] = explode(',',$array[i])
if($str == $arr_values[$i][0]) // Match the First String with the required string
{
//On match return the array with the values contained in it
return array($arr_values[$i][1], $arr_values[$i][2]);
}
}
}
Now
$required_arr['Would'] // will hold Array([0] => 22 [1] => 22)
Write a function to search the array. This should work well enough
<?php
// test array
$arr = array('Title,11,11','Would,22,22','Post,55,55','Ask,66,66');
// define search function that you pass an array and a search string to
function search($needle,$haystack){
// loop over each passed in array element
foreach($haystack as $v){
// if there is a match at the first position
if(strpos($v,$needle) === 0)
// return the current array element
return $v;
}
// otherwise retur false if not found
return false;
}
// test the function
echo search("Would",$arr);
?>
are the indices important ? why not ..
$arr = array(
'Title' => array(11, 11),
'Would' => array(22, 22),
'Post' => array(55, 55),
'Ask' => array(66,66)
);
$send = "Title"; // for example
$result = $arr[$send];
How about using something like, so you don't loop trough entire array:
$array = array( "Title,11,11", "Would,22,22", "Post,55,55", "Ask,66,66" );
$key = my_array_search('Would', $array);
$getvalues = explode(",", $array[$key]);
function my_array_search($needle = null, $haystack_array = null, $skip = 0)
{
if($needle == null || $haystack_array == null)
die('$needle and $haystack_array are mandatory for function my_array_search()');
foreach($haystack_array as $key => $eval)
{
if($skip != 0)$eval = substr($eval, $skip);
if(stristr($eval, $needle) !== false) return $key;
}
return false;
}