How to remove the extension from the array key, ie .md.
It should look like this key: [about] => pages/about.md
Array:
Array:
(
[_desktop.md] => pages/_desktop.md
[about.md] => pages/about.md
[contact.md] => pages/contact.md
[errorpages] => Array
(
[403.md] => pages/errorpages/403.md
[404.md] => pages/errorpages/404.md
[500.md] => pages/errorpages/500.md
[503.md] => pages/errorpages/503.md
)
[home.md] => pages/home.md
[indexpage.md] => pages/indexpage.md
)
Code:
function generatePathTree($dir) {
$pathstack = array($dir);
$contentsroot = array();
$contents = &$contentsroot;
while ($path = array_pop($pathstack)) {
$contents[basename($path)] = array();
$contents = &$contents[basename($path)];
foreach (scandir($path) as $filename) {
if ('.' != substr($filename, 0, 1)) {
$newPath = $path.'/'.$filename;
if (is_dir($newPath)) {
array_push($pathstack, $newPath);
$contents[basename($newPath)] = array();
} else {
$contents[basename($filename)] = $newPath;
}
}
$contentsroot = preg_replace("/\\.[^.]*$/", "", basename($filename));
}
}
return $contentsroot[basename($dir)];
}
I tried so:
$contentsroot = preg_replace("/\\.[^.]*$/", "", basename($filename));
But alas.
How to do?
In this code block (This is where filename gets assigned instead of dir):
else {
$fileExtRemoved = preg_replace("/[\.](.*)/", "", $filename);
$contents[basename($fileExtRemoved)] = $newPath;
}
Your regexp is a little bit off, this is the correct one:
https://3v4l.org/mMPrt
You can assigne the old value to new key and then unset the old key
$arr['about'] = $arr['about.md'];
unset($arr['about.md']);
It's three characters on all of them?
So why not just use sub_str($key , 0, -3);?
If it's always three chars it should work, and as I see it, it seems to be three.
So maybe:
$contents[basename(substr($filename,0,-3))];
Requirement: remove any part of the array key string after the first . if it exists in the string.
Solution:
list($key,) = explode('.', $old_key);
$arr[$key] = $arr[$old_key];
unset($arr[$old_key]);
A side note: there must be a better way to do the recursive loop. But a quick look suggests that array_walk_recursive only operates on the leaf nodes; array_map and array_reduce don't have recursive variants and they only take values anyway. Since you didn't explicitly ask for this, I'll stop there.
Related
I have a string 'value1/value2'. The required output is $_SESSION['value1']['value2']. i tried using explode and then array_reduce over explode values but with no success.
My code looks like
function set($key, $value){
/* code */
}
set('key1/key2', 'some_text');
required output like $_SESSION['key1']['key2'] = 'some_text';
key1/key2 is not fixed it may be 'key1' or 'key1/key2/key3' and so on.
Anyone be make fiddle of it is Highly appreciable.
Thanks
Accessing a value via a key-path string, as in your original question, using your original idea and let array_reduce do the work looks like:
$session = ['value1' => [ 'value2' => [ 'value3' => 'there you are!' ]]];
$path = explode('/', 'value1/value2/value3');
$val = array_reduce($path,
function(&$carry, $key) { return $carry[$key];},
$session);
echo $val
--> "there you are!"
Setting a value can be done e.g. like this, following the path by reference, creating arrays as needed:
function set($path, $value) {
$path = explode('/', $path);
$key = array_pop($path);
$arr = &$_SESSION;
foreach($path as $part) {
// carefull, this might lose values to accommodate
// the structure wanted with $path
(isset($arr[$part]) && is_array($arr[$part])) || ($arr[$part] = []);
$arr =& $arr[$part];
}
$arr[$key] = $value;
};
Try this
<?php
session_start();
$string = 'value1/value2';
$array = explode("/",$string);
$_SESSION[$array[0]][$array[1]] = "ccccccc";//$_SESSION['value1']['value2']
For a general case (i.e. for more than two pieces), you'll need to iterate over the segments, and incrementally index further into your target array:
<?php
$string = 'value1/value2/value3';
$_SESSION = ['value1' => ['value2' => ['value3' => 'My String']]];
$target = $_SESSION;
foreach (explode('/', $string) as $piece) {
$target =& $target[$piece];
}
echo $target; // My String
I have an array of strings, each string containing the name of an image file:
$slike=(1.jpg,253455.jpg,32.jpg,477.jpg);
I want new array, to look like this:
$slike=(1,253455,32,477);
How can I remove the file extension from each string in this array?
If you're working with filenames, use PHP's built in pathinfo() function. there's no need to use regex for this.
<?php
# your array
$slike = array('1.jpg','253455.jpg','32.jpg','477.jpg');
# if you have PHP >= 5.3, I'd use this
$slike = array_map(function($e){
return pathinfo($e, PATHINFO_FILENAME);
}, $slike);
# if you have PHP <= 5.2, use this
$slike = array_map('pathinfo', $slike, array_fill(
0, count($slike), PATHINFO_FILENAME
));
# dump
print_r($slike);
Output
Array
(
[0] => 1
[1] => 253455
[2] => 32
[3] => 477
)
Using preg_split in foreach
foreach ($slike as &$value) {
$split = preg_split('/\./', $value);
$value = $split[0]
}
Change the regex to /[^.]+/ to include a.b.jpg as well.
Regular expressions are your friend on this one. I'm assuming that by brackers, you mean an array.
$k = count($slike);
for ($i = 0; $i < $k; $i++) {
$extpos = strrpos($slike[$i],".");
$slike[$i] = substr($slike[$i],0,$extpos);
}
This is no longer regex-dependent, and benchmarks faster than pathinfo().
Try this one:
$slike = array('1.jpg','253455.jpg','32.jpg','477.jpg');
$slike = array_map(function($e){
$e = explode('.', $e);
return $e[0];
}, $slike);
echo "<pre>";
print_r($slike);
echo "</pre>";
I have a bunch of files named like this...
full-file(1).jpg
full-file(10).jpg
full-file(11).jpg
full-file(12).jpg
full-file(2).jpg
etc...
I'm trying to figure out the most efficient way to rename all these files using PHP so that they get renamed like this...
full-file0001.jpg
full-file0010.jpg
full-file0011.jpg
full-file0012.jpg
full-file0002.jpg
I've got as far as reading all the files from a folder and looping through them but not sure about the best way to remove the brackets and make the number 4 digits with leading 0.
$image_files = get_files($thumbpath);
foreach($image_files as $index=>$file) {
echo $file;
}
Use a regular expression to get the digit, and then zero-pad it using sprintf():
$image_files = get_files($thumbpath);
foreach($image_files as $index=>$file) {
// Capture \d+ into $matches[1]
preg_match('/\((\d+)\)/', $file, $matches);
// Pad it with %04d in sprintf()
$newfile = sprintf("full-file%04d.jpg", $matches[1]);
}
Example:
php > $file = 'full-file(12).jpg';
php > preg_match('/\((\d+)\)/', $file, $matches);
php > $newfile = sprintf("full-file%04d.jpg", $matches[1]);
php > echo $newfile;
// full-file0012.jpg
Update (for more flexible filenames):
To please the downvoter I can only assume wanted more flexible filenames, expand the regular expression:
$image_files = get_files($thumbpath);
foreach($image_files as $index=>$file) {
preg_match('/([^(]+)\((\d+)\)(.+)/', $file, $matches);
$newfile = sprintf("%s%04d%s", $matches[1], $matches[2], $matches[3]);
// And rename the file
if (!rename($file, $newfile)) {
echo "Could not rename $file.\n";
}
else echo "Successfully renamed $file to $newfile\n";
}
The pattern matches first, everything up to the the first ( with ([^(]+), followed by the number via (\d+), and everything remaining via (.*).
You can use a mixture of REGEXP (remove brackets) and string padding (to force four digits).
Note I use a replacement callback to do both operations in one place.
$files = array(
'full-file(1).jpg',
'full-file(10).jpg',
'full-file(11).jpg',
'full-file(12).jpg',
'full-file(2).jpg'
);
function pr_callback($match) {
return str_pad($match[1], 4, '0', STR_PAD_LEFT);
}
foreach($files as $file)
echo preg_replace_callback('/\((\d+)\)/', pr_callback, $file).'<br />';
Outputs:
full-file0001.jpg
full-file0010.jpg
full-file0011.jpg
full-file0012.jpg
full-file0002.jpg
I haven't seen anyone recommend sscanf() yet.
<?php
$files = array(
"full-file(1).jpg",
"full-file(10).jpg",
"full-file(11).jpg",
"full-file(12).jpg",
"full-file(2).jpg",
);
foreach ($files as $file) {
$n = sscanf($file, "full-file(%d).jpg");
printf("full-file%04d.jpg\n", $n[0]);
}
returns:
full-file0001.jpg
full-file0010.jpg
full-file0011.jpg
full-file0012.jpg
full-file0002.jpg
This only works if "full-file" is the actual name of your file, of course. sscanf() is not a regex parser, it merely extracts data using printf()-style format strings ... though it does do some more advanced format recognition than is documented at http://php.net/sscanf . If you need to handle other filenames, you can extend the format string:
<?php
$files = array(
"this-file(1).jpg",
"full-file(10).jpg",
"foo(11).jpg",
"blarg(12).jpg",
"full-file(2).jpg",
);
foreach ($files as $file) {
$n = sscanf($file, "%[a-z-](%d).jpg");
printf("%s%04d.jpg\n", $n[0], $n[1]);
}
returns:
this-file0001.jpg
full-file0010.jpg
foo0011.jpg
blarg0012.jpg
full-file0002.jpg
Assuming your files aren't actually called full-file(0000).jpg:
<?php
$arr = array('full-file(1).jpg',
'full-file(10).jpg',
'full-file(11).png',
'full-file(12).jpg',
'full-file(2).gif',
'abc(12345).jpg',
'def(99).jpg',
'xzy-file(100).jpg');
function format_filename($matches){
return $matches[1].sprintf("%04d",$matches[3]).'.'.$matches[5];
}
function process_array(&$value){
$value = preg_replace_callback('/^(.*?)(\()(\d+)(\)).(jpg|png|gif)/','format_filename',$value);
}
array_walk($arr,'process_array');
print_r($arr);
/*
Array
(
[0] => full-file0001.jpg
[1] => full-file0010.jpg
[2] => full-file0011.png
[3] => full-file0012.jpg
[4] => full-file0002.gif
[5] => abc12345.jpg
[6] => def0099.jpg
[7] => xzy-file0100.jpg
)
*/
?>
Use code:
preg_match('/^(.*?)\((\d+)\)(.*)$/', $name, $m);
$name = sprintf("%s%04d%s", $m[1], $m[2], $m[3]);
See and test it here.
You will need str-pad(). A sample soon...
EDIT 1: solution using str_pad and preg_replace_callback.
OBS: Anonymous functions only in php5.3+.
foreach ($image_files as $file)
{
$o = preg_replace_callback(
"|\((\d+)\)|", function($matches)
{
$r = str_pad($matches[1], 4, '0', STR_PAD_LEFT);
return $r;
}
, $file);
echo $o . "\n";
}
I have been looking around for a while in the PHP manual and can't find any command that does what I want.
I have an array with Keys and Values, example:
$Fields = array("Color"=>"Bl","Taste"=>"Good","Height"=>"Tall");
Then I have a string, for example:
$Headline = "My black coffee is cold";
Now I want to find out if any of the array ($Fields) values match somewhere in the string ($Headline).
Example:
Array_function_xxx($Headline,$Fields);
Would give the result true because "bl" is in the string $Headline (as a part of "Black").
I'm asking because I need performance... If this isn't possible, I will just make my own function instead...
EDIT - I'm looking for something like stristr(string $haystack , array $needle);
Thanks
SOLUTION - I came up with his function.
function array_in_str($fString, $fArray) {
$rMatch = array();
foreach($fArray as $Value) {
$Pos = stripos($fString,$Value);
if($Pos !== false)
// Add whatever information you need
$rMatch[] = array( "Start"=>$Pos,
"End"=>$Pos+strlen($Value)-1,
"Value"=>$Value
);
}
return $rMatch;
}
The returning array now have information on where each matched word begins and ends.
This should help:
function Array_function_xxx($headline, $fields) {
$field_values = array_values($fields);
foreach ($field_values as $field_value) {
if (strpos($headline, $field_value) !== false) {
return true; // field value found in a string
}
}
return false; // nothing found during the loop
}
Replace name of the function with what you need.
EDIT:
Ok, alternative solution (probably giving better performance, allowing for case-insensitive search, but requiring proper values within $fields parameter) is:
function Array_function_xxx($headline, $fields) {
$regexp = '/(' . implode('|',array_values($fields)) . ')/i';
return (bool) preg_match($regexp, $headline);
}
http://www.php.net/manual/en/function.array-search.php
that's what you looking for
example from php.net
<?php
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search('green', $array); // $key = 2;
$key = array_search('red', $array); // $key = 1;
?>
I am trying to create a multi-dimensional array whose parts are determined by a string. I'm using . as the delimiter, and each part (except for the last) should be an array
ex:
config.debug.router.strictMode = true
I want the same results as if I were to type:
$arr = array('config' => array('debug' => array('router' => array('strictMode' => true))));
This problem's really got me going in circles, any help is appreciated. Thanks!
Let’s assume we already have the key and value in $key and $val, then you could do this:
$key = 'config.debug.router.strictMode';
$val = true;
$path = explode('.', $key);
Builing the array from left to right:
$arr = array();
$tmp = &$arr;
foreach ($path as $segment) {
$tmp[$segment] = array();
$tmp = &$tmp[$segment];
}
$tmp = $val;
And from right to left:
$arr = array();
$tmp = $val;
while ($segment = array_pop($path)) {
$tmp = array($segment => $tmp);
}
$arr = $tmp;
I say split everything up, start with the value, and work backwards from there, each time through, wrapping what you have inside another array. Like so:
$s = 'config.debug.router.strictMode = true';
list($parts, $value) = explode(' = ', $s);
$parts = explode('.', $parts);
while($parts) {
$value = array(array_pop($parts) => $value);
}
print_r($parts);
Definitely rewrite it so it has error checking.
Gumbo's answer looks good.
However, it looks like you want to parse a typical .ini file.
Consider using library code instead of rolling your own.
For instance, Zend_Config handles this kind of thing nicely.
I really like JasonWolf answer to this.
As to the possible errors: yes, but he supplied a great idea, now it is up to the reader to make it bullet proof.
My need was a bit more basic: from a delimited list, create a MD array. I slightly modified his code to give me just that. This version will give you an array with or without a define string or even a string without the delimiter.
I hope someone can make this even better.
$parts = "config.debug.router.strictMode";
$parts = explode(".", $parts);
$value = null;
while($parts) {
$value = array(array_pop($parts) => $value);
}
print_r($value);
// The attribute to the right of the equals sign
$rightOfEquals = true;
$leftOfEquals = "config.debug.router.strictMode";
// Array of identifiers
$identifiers = explode(".", $leftOfEquals);
// How many 'identifiers' we have
$numIdentifiers = count($identifiers);
// Iterate through each identifier backwards
// We do this backwards because we want the "innermost" array element
// to be defined first.
for ($i = ($numIdentifiers - 1); $i >=0; $i--)
{
// If we are looking at the "last" identifier, then we know what its
// value is. It is the thing directly to the right of the equals sign.
if ($i == ($numIdentifiers - 1))
{
$a = array($identifiers[$i] => $rightOfEquals);
}
// Otherwise, we recursively append our new attribute to the beginning of the array.
else
{
$a = array($identifiers[$i] => $a);
}
}
print_r($a);