How do I apply a replace to each array element in PHP? - php

I have an array with a list of all controllers in my application:
$controllerlist = glob("../controllers/*_controller.php");
How do I strip ../controllers/ at the start and _controller.php at the end of each array element with one PHP command?

As preg_replace can act on an array, you could do:
$array = array(
"../controllers/test_controller.php",
"../controllers/hello_controller.php",
"../controllers/user_controller.php"
);
$array = preg_replace('~../controllers/(.+?)_controller.php~', "$1", $array);
print_r($array);
output:
Array
(
[0] => test
[1] => hello
[2] => user
)

Mapping one array to another:
$files = array(
'../controllers/test_controller.php',
'../controllers/hello_controller.php'
);
$start = strlen('../controllers/');
$end = strlen('_controller.php') * -1;
$controllers = array_map(
function($value) use ($start, $end) {
return substr($value, $start, $end);
},
$files
);
var_dump($controllers);

I'm not sure how you defined "command", but I doubt there is a way to do that with one simple function call.
However, if you're simply wanting it to be compact, here's a simple way of doing it:
$controllerlist = explode('|||', str_replace(array('../controllers/', '_controller.php'), '', implode('|||', glob("../controllers/*_controller.php"))));
It's a bit dirty, but it gets the job done in a single line.

One command without searching and replacing? Yes you can!
If I'm not missing something grande, what about keeping it simple and chopping 15 characters from the start and the end using the substr function:
substr ( $x , 15 , -15 )
Since glob will always give you strings with that pattern.
Example:
// test array (thanks FruityP)
$array = array(
"../controllers/test_controller.php",
"../controllers/hello_controller.php",
"../controllers/user_controller.php" );
foreach($array as $x){
$y=substr($x,15,-15); // Chop 15 characters from the start and end
print("$y\n");
}
Output:
test
hello
user

No need for regex in this case unless there can be variations of what you mentioned.
$array = array(
"../controllers/test_controller.php",
"../controllers/hello_controller.php",
"../controllers/user_controller.php"
);
// Actual one liner..
$list = str_replace(array('../controllers/', '_controller.php'), "", $array);
var_dump($array);
This will output
array (size=3)
0 => string 'test' (length=4)
1 => string 'hello' (length=5)
2 => string 'user' (length=4)
Which is (I think) what you asked for.

If you have an array like this :
$array = array( "../controllers/*_controller.php",
"../controllers/*_controller.php");
Then array_map() help you to trim the unnecessary string.
function trimmer( $string ){
return str_replace( "../controllers/", "", $string );
}
$array = array( "../controllers/*_controller.php",
"../controllers/*_controller.php");
print_r( array_map( "trimmer", $array ) );
http://codepad.org/VO6kyVOa

to strip 15 chars at the start and 15 at the end of each arrayelement in one command:
$controllerlist = substr_replace(
substr_replace(
glob("../controllers/*_controller.php"),'',-15
),'',0,15
)

preg_replace accepts an array as argument too:
$before = '../controllers/';
$after = "_controller.php";
$preg_str = preg_quote($before,"/").'(.*)'.preg_quote($after,"/");
$controllerlist = preg_replace('/^'.$preg_str.'$/', '\1', glob("$before*$after"));

Related

How to get an associative array from a string?

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.

preg_split how to transform the delimiter as index using php

I have this cases with strings in PHP:
*nJohn*sSmith*fGeorge#*nHenry*sFord
and wish to create an array with
[name],[surname],[fathers] as indexes so it will produce
name_array[1] = (
[name] => 'John',
[surname] => 'Smith',
[fathers] => 'George'
)
name_array[2]=(
[name] => 'Henry',
[surname] => 'Ford'
)
and so on.
How to do it using preg_split in PHP??
Thanks!
I'd use preg_match_all to get the names. If your string is consistent I think you could do:
$string = '*nJohn*sSmith*fGeorge#*nHenry*sFord';
preg_match_all('/\*n(?<givenname>.*?)\*s(?<surname>.*?)(?:\*f(?<middlename>.*?))?(?:#|$)/', $string, $matches);
print_r($matches);
Regex demo: https://regex101.com/r/1hKzvM/1/
PHP demo: https://eval.in/784879
Solution without using regex:
$string = '*nJohn*sSmith*fGeorge#*nHenry*sFord';
$result = array();
$persons = explode('#', $string);
foreach ($persons as $person) {
$identials = explode('*', $person);
unset($r);
foreach ($identials as $idential) {
if(!$idential){
continue; //empty string
}
switch ($idential[0]) { //first character
case 'n':
$key = 'name';
break;
case 's':
$key = 'surename';
break;
case 'f':
$key = 'fathers';
break;
}
$r[$key] = substr($idential, 1);
}
$result[] = $r;
}
This function will produce the result that you want ! but consider it's not the only way and not the 100% correct way ! i used preg_split as u asked
function splitMyString($str){
$array_names = [];
$mainString = explode('#', $str);
$arr1 = preg_split("/\*[a-z]/", $mainString[0]);
unset($arr1[0]);
$arr1_values = array_values($arr1);
$arr1_keys = ['name','surname','fathers'];
$result1 = array_combine($arr1_keys, $arr1_values);
// second part of string
$arr2 = preg_split("/\*[a-z]/", $mainString[1]);
unset($arr2[0]);
$arr2_values = array_values($arr2);
$arr2_keys = ['name','surname'];
$arr2 = array_combine($arr2_keys, $arr2_values);
$array_names[] = $arr1;
$array_names[] = $arr2;
return $array_names;
}
// test result !
print_r(splitMyString("*nJohn*sSmith*fGeorge#*nHenry*sFord"));
thanks to all!
For some reason the site blocks my voting for some 'reputation' reason which I find not-fully democracy compliant! On the other hand who cares about democracy these days!
Nevertheless I am using solution #2, without indicating that solution 1 or 3 are not great!
Regards.
However inspired by your answers I came up with mine also, here it is!
$string = '*nJohn*sSmith*fGeorge#*nHenry*sFord';
split_to_key ( $string, array('n'=>'Name','s'=>'Surname','f'=>'Middle'));
function split_to_key ( $string,$ind=array() )
{
$far=null;
$i=0;
$fbig=preg_split('/#/',$string,-1,PREG_SPLIT_NO_EMPTY);
foreach ( $fbig as $fsmall ) {
$f=preg_split('/\*/u',$fsmall,-1,PREG_SPLIT_NO_EMPTY);
foreach ( $f as $fs ) {
foreach( array_keys($ind) as $key ) {
if( preg_match ('/^'.$key.'/u',$fs ) ) {
$fs=preg_replace('/^'.$key.'/u','',$fs);
$far[$i][$ind[$key]]=$fs;
}
}
}
$i++;
}
print_r($far);
}
Like Chris, I wouldn't use preg_split(). My method uses just one preg() function and one loop to completely prepare the filtered output in your desired format (notice my output is 0-indexed, though).
Input (I extended your input sample for testing):
$string='*nJohn*sSmith*fGeorge#*nHenry*sFord#*nJames*sWashington#*nMary*sMiller*fRichard';
Method (PHP Demo & Regex Demo):
if(preg_match_all('/\*n([^*]*)\*s([^*]*)(?:\*f([^#]*))?(?=#|$)/', $string, $out)){
$out=array_slice($out,1); // /prepare for array_column()
foreach($out[0] as $i=>$v){
$name_array[$i]=array_combine(['name','surname','father'],array_column($out,$i));
if($name_array[$i]['father']==''){unset($name_array[$i]['father']);}
}
}
var_export($name_array);
Output:
array (
0 =>
array (
'name' => 'John',
'surname' => 'Smith',
'father' => 'George',
),
1 =>
array (
'name' => 'Henry',
'surname' => 'Ford',
),
2 =>
array (
'name' => 'James',
'surname' => 'Washington',
),
3 =>
array (
'name' => 'Mary',
'surname' => 'Miller',
'father' => 'Richard',
),
)
My regex pattern is optimized for speed by using "negative character classes". I elected to not use the named capture groups because they nearly double the output array size from preg_match_all() and that array requires further preparation anyhow.

How to get value from nested array using string

I have an array like this:
$temp = array( '123' => array( '456' => array( '789' => '0' ) ),
'abc' => array( 'def' => array( 'ghi' => 'jkl' ) )
);
I have a string like this:
$address = '123_456_789';
Can I get value of $temp['123']['456']['789'] using above array $temp and string $address?
Is there any way to achieve this and is it good practice to use it?
This is a simple function that accepts an array and a string address where the keys are separated by any defined delimiter. With this approach, we can use a for-loop to iterate to the desired depth of the array, as shown below.
<?php
function delimitArray($array, $address, $delimiter="_") {
$address = explode($delimiter, $address);
$num_args = count($address);
$val = $array;
for ( $i = 0; $i < $num_args; $i++ ) {
// every iteration brings us closer to the truth
$val = $val[$address[$i]];
}
return $val;
}
$temp = array("123"=>array("456"=>array("789"=>"hello world")));
$address = "123_456_789";
echo delimitArray($temp,$address,"_");
?>
Hello if string $address = '123_456_789'; is your case then you can use explode function to split the string by using some delimeter and you can output your value
<?php
$temp = array('123' => array('456' => array('789' => '0')),
'abc' => array('def' => array('ghi' => 'jkl')),
);
$address = '123_456_789';
$addr = explode("_", $address);
echo $temp[$addr[0]][$addr[1]][$addr[2]];
Using this array library you can easily get element value by either converting your string to array of keys using explode:
Arr::get($temp, explode('_', $address))
or replacing _ with . to take advantage of dot notation access
Arr::get($temp, str_replace('_', '.', $address))
Another benefit of using this method is that you can set default fallback value to return if element with given keys does not exists in array.

Converting string into array in php

I have string like below
["Day1"]["Morning"]=mutton&["Day1"]["Evening"]=Juice&["Day2"]["Morning"]=burger&["Day2"]["Evening"]=pizza
Which i am trying to convert into array like below
$arr["Day1"]["Morning"] = "mutton";
$arr["Day1"]["Evening"] = "Juice";
$arr["Day2"]["morning"] = "burger";
$arr["Day2"]["evening"] = "pizza";
I tried something like below.
$str = '["Day1"]["Morning"]=mutton&["Day1"]["Evening"]=Juice&["Day2"]["Morning"]=burger&["Day2"]["Evening"]=pizza';
$pieces = explode("&", $str);
foreach($pieces as $pie)
{
$arr.$pie;
}
var_dump($arr);
I know above code is really dumb :/ .Is there any proper solution for this ?
You could do like this...
<?php
$str='["Day1"]["Morning"]=mutton&["Day1"]["Evening"]=Juice&["Day2"]["Morning"]=burger&["Day2"]["Evening"]=pizza';
$arr = explode('&',$str);
foreach($arr as $v)
{
$valarr=explode('=',$v);
preg_match_all('/"(.*?)"/', $valarr[0], $matches);
$narr[$matches[1][0]][$matches[1][1]]=$valarr[1];
}
print_r($narr);
OUTPUT :
Array
(
[Day1] => Array
(
[Morning] => mutton
[Evening] => Juice
)
[Day2] => Array
(
[Morning] => burger
[Evening] => pizza
)
)
You could access like echo $arr["Day1"]["Morning"] which prints mutton
Demo
It looks like it could be parsed with parse_str(), but not without some conversion:
$str = '["Day1"]["Morning"]=mutton&["Day1"]["Evening"]=Juice&["Day2"]["Morning"]=burger&["Day2"]["Evening"]=pizza';
parse_str(preg_replace('/(?<=^|&)/', 'x', str_replace('"', '', $str)), $a);
var_dump($a['x']);
It removes the double quotes, prefixes each entry with x and then applies parse_str(). To get an idea of what the preg_replace() does, the intermediate result is this:
x[Day1][Morning]=mutton&x[Day1][Evening]=Juice&x[Day2][Morning]=burger&x[Day2][Evening]=pizza
Parsing the above string yields an array with a single root element x.

Why does php str_replace with multiple arrays give wrong result, but for loop gives correct result?

I'm trying to replace the characters (numbers and letters) in a string. When I try the "php" way, it gives the wrong result for some of the characters. Why?
PHP-WAY:
$find = array( "0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f" );
$replace = array( "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p" );
$haystack = "a5c9a06bfacf5f12cf01ab3f202f6c78"
//This incorrectly returns: kpmjkkglpkmppplmmpklklnpmkmpgmhi
echo str_replace( $find, $replace, $haystack );
LOOP WAY:
$find = array( "0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f" );
$replace = array( "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p" );
$haystack = "a5c9a06bfacf5f12cf01ab3f202f6c78"
//This correctly returns: kfmjkaglpkmpfpbcmpabkldpcacpgmhi
$newStr = "";
$chars = str_split( $haystack );
for ( $i = 0, $length = count( $chars ); $i < $length; $i++ )
{
$newStr .= $replace[ array_search( $chars[ $i ], $find ) ];
}
echo $newStr;
Why is the first one incorrect? Am I using it wrong?
Order of entries in your arrays.... str_replace() will process each array entry in the order they appear in your array, so if a '1' gets replaced with 'b', then that 'b' will subsequently get replaced with 'l'; use strtr() rather than str_replace() if you want to prevent that behaviour.
$find = array( "0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f" );
$replace = array( "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p" );
$haystack = "a5c9a06bfacf5f12cf01ab3f202f6c78" ;
echo strtr($haystack, array_combine($find, $replace));
Your own code only does a single replace because it's looping against your string, not against the from/to arrays.
Just use strtr
$haystack = "a5c9a06bfacf5f12cf01ab3f202f6c78" ;
echo strtr($haystack, implode($find), implode($replace));
Or preg_replace_callback
$find = array_flip($find);
echo preg_replace_callback('/[a-f0-9]/', function ($v) use($replace, $find) {
return $replace[$find[$v[0]]];
}, $haystack);
Output
kfmjkaglpkmpfpbcmpabkldpcacpgmhi
As specified by #MarkBaker, the answer is that str_replace does not simply move forward in the string, but instead works like a recursive .replace(). Instead, use strtr (which is equivalent to Linux tr command:
$tr = array( "0" => "a","1" => "b","2" => "c","3" => "d","4" => "e","5" => "f","6" => "g","7" => "h","8" => "i","9" => "j","a" => "k","b" => "l","c" => "m","d" => "n","e" => "o","f" => "p" );
$haystack = "a5c9a06bfacf5f12cf01ab3f202f6c78"
echo strtr( $haystack, $tr );

Categories