Разбить строку на массив и добавить предыдущее значение
У меня есть эта строка:
вар/Журнал /file.log
В конце концов я хочу получить массив, похожий на этот:
Array => [
'1' => 'var',
'2' => 'var/log',
'3' => 'var/log/file.log'
]
В настоящее время у меня есть это:
<?php
$string = 'var/log/file.log';
$array = explode('/', $string);
$output = [
1 => $array[0],
2 => $array[0]. '/' .$array[1],
3 => $array[0]. '/' .$array[1]. '/' .$array[2]
];
echo '<pre>'. print_r($output, 1) .'</pre>';
Это кажется действительно нелогичным, и я не уверен, что в PHP уже есть что-то, что может позаботиться об этом.
Как построить массив, используя добавление предыдущего значения?
Ответы
Ответ 1
В этом решении используется подход, начинающийся с вашего входного пути, а затем удаляя путь один за другим, добавляя оставшиеся входные данные в массив на каждом шаге. Затем мы обращаем массив в качестве последнего шага, чтобы сгенерировать желаемый результат.
$input = "var/log/file.log";
$array = [];
while (preg_match("/\//i", $input)) {
array_push($array, $input);
$input = preg_replace("/\/[^\/]+$/", "", $input);
echo $input;
}
array_push($array, $input);
$array = array_reverse($array);
print_r($array);
Array
(
[0] => var
[1] => var/log
[2] => var/log/file.log
)
Вышеуказанный вызов preg_replace
удаляет окончательный путь входной строки, включая косую черту. Это повторяется до тех пор, пока не останется только один конечный компонент пути. Затем мы добавляем этот последний компонент в тот же массив.
Ответ 2
<?php
$string = 'var/log/some/other/directory/file.log';
$array = explode('/', $string);
$i = 0;
foreach ($array as $data) {
$output[] = isset($output) ? $output[$i - 1] . '/' . $data : $data;
$i++;
}
echo '<pre>';
print_r($output);
Более простое решение выше. Вы просто устанавливаете в своем новом поле массива конкатенацию предыдущего поля из нового массива и текущего из вашего foreach
.
Выход:
Array
(
[0] => var
[1] => var/log
[2] => var/log/some
[3] => var/log/some/other
[4] => var/log/some/other/directory
[5] => var/log/some/other/directory/file.log
)
Ответ 3
Вы можете сделать что-то подобное с foreach
<?php
$string = 'var/log/file.log';
$array = explode('/', $string);
$last = '';
$output = array();
foreach ($array as $key => $value) {
$result = $last.$value;
$output[$key] = $result;
$last = $result.'/';
}
echo '<pre>'. print_r($output, 1) .'</pre>';
Ответ 4
Вы можете получить родительский каталог в цикле и добавить его в output
переменную. Например с помощью следующего алгоритма:
$path = 'var/log/file.log';
$output = [];
$pos = strlen($path);
while ($pos !== false) {
$path = substr($path, 0, $pos);
array_unshift($output, $path);
$pos = strrpos($path, DIRECTORY_SEPARATOR);
}
или с помощью функции dirname()
$path = 'var/log/file.log';
$output = [];
do {
array_unshift($output, $path);
$path = dirname($path);
} while ($path !== '.');
Также вы можете работать со строкой $path
как с массивом символов и находить в нем разделитель каталогов:
$path = 'var/log/file.log';
$output = [];
$tmp = '';
$len = strrpos($path, DIRECTORY_SEPARATOR); // you can use strlen instead of strrpos,
// but it'll look over filename also
for ($i = 0; $i < $len; $i++) {
if ($path[$i] === DIRECTORY_SEPARATOR) {
$output[] = $tmp;
}
$tmp .= $path[$i];
}
$output[] = $path;
но имейте в виду, что вы не можете использовать этот способ, если строка $path
имеет многобайтовую кодировку
Результатом всех методов будет:
Array (
[0] => var
[1] => var/log
[2] => var/log/file.log
)
Ответ 5
Здесь уже есть много хороших ответов, но здесь есть еще один немного другой способ сделать это:
$string = 'var/log/some/other/directory/file.log';
$array = explode('/', $string);
for ($c = count($array); $c > 0; ) {
$output[--$c] = implode('/', $array);
array_pop($array);
}
for ($i = 0; $i < count($output); $i++) {
echo "$output[$i]\n";
}
Выход:
var
var/log
var/log/some
var/log/some/other
var/log/some/other/directory
var/log/some/other/directory/file.log
Демо на 3v4l.org
Ответ 6
В качестве альтернативы:
<?php
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'On');
$input = 'var/log/file.log';
$output = explode('/', $input);
for ($i = 1, $lim = \count($output); $i < $lim; $i++) {
$output[$i] = $output[$i - 1] . '/' . $output[$i];
}
print_r($output);
https://3v4l.org/Ng2fJ
Ответ 7
Поскольку я не могу с собой поделать, я оценил все эти ответы. Ответ @Yoshi (удален, но вы можете увидеть код ниже) был довольно ясным, затем следовали @OliverNybo (примерно на 15% медленнее), @pr1nc3 (примерно на 35% медленнее), пробел в шахте и @MaximFedorov сначала и во-вторых ответ (примерно на 55-75% медленнее), затем еще один пробел в @TimBiegeleisen и, наконец, в @MaximFedorov последний ответ (который фактически не возвращал правильный результат). Вот результаты для 100 000 итераций (раз в секундах):
Здесь код тестирования. Примечание. Я удалил вызов array_reverse
где он использовался, поскольку он не выполняет ничего, кроме изменения порядка вывода.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
table {
border-collapse: collapse;align-content:
}
td, th {
border: 1px solid black;
padding: 5px;
}
</style>
</head>
<body>
<pre>
<?php
$string = 'var/log/some/other/directory/file.log';
$elapsed = array();
foreach (array('TimBiegeleisen', 'pr1nc3', 'OliverNybo', 'MaximFedorov1', 'MaximFedorov2', 'MaximFedorov3', 'Nick') as $func) {
$start = explode(' ', microtime());
for ($i = 0; $i < 100000; $i++) $func($string);
$elapsed[$func] = elapsed_time($start);
}
asort($elapsed);
$fastest = min($elapsed);
echo "<table><tr><th>Function</th><th>Elapsed Time</th><th>Delta</tr>";
foreach ($elapsed as $key => $value) {
echo "<td>$key</td><td>$value</td>";
echo "<td>" . sprintf("%.0f%%", ($value - $fastest) / $fastest * 100) . "</td></tr>";
}
echo "</table>\n";
function TimBiegeleisen($input) {
$array = [];
while (preg_match("/\//i", $input)) {
array_push($array, $input);
$input = preg_replace("/\/[^\/]+$/", "", $input);
}
array_push($array, $input);
return $array;
// return array_reverse($array);
}
function pr1nc3($string) {
$array = explode('/', $string);
$i = 0;
foreach ($array as $data) {
$output[] = isset($output) ? $output[$i - 1] . '/' . $data : $data;
$i++;
}
return $output;
}
function OliverNybo($string) {
$array = explode('/', $string);
$last = '';
$output = array();
foreach ($array as $key => $value) {
$result = $last.$value;
$output[$key] = $result;
$last = $result.'/';
}
return $output;
}
function MaximFedorov1($path) {
$output = [];
$pos = strlen($path);
while ($pos !== false) {
$path = substr($path, 0, $pos);
array_unshift($output, $path);
$pos = strrpos($path, '/');
}
return $output;
}
function MaximFedorov2($path) {
$output = [];
do {
array_unshift($output, $path);
$path = dirname($path);
} while ($path !== '.');
return $output;
}
function MaximFedorov3($path) {
$output = [];
$tmp = '';
$len = strrpos($path, '/'); // you can use strlen instead of strrpos,
// but it'll look over filename also
for ($i = 0; $i < $len; $i++) {
if ($path[$i] === '/') {
$output[] = $tmp;
}
$tmp .= $path[$i];
}
$output[] = $path;
return $output;
}
function Nick($string) {
$array = explode('/', $string);
for ($c = count($array); $c > 0; ) {
$output[--$c] = implode('/', $array);
array_pop($array);
}
return $output;
// return array_reverse($output)
}
function Yoshi($input) {
$output = explode('/', $input);
for ($i = 1, $lim = \count($output); $i < $lim; $i++) {
$output[$i] = $output[$i - 1] . '/' . $output[$i];
}
return $output;
}
function elapsed_time(array $start) {
$now = explode(' ', microtime());
$deltasec = $now[1] - $start[1];
$deltamsec = (float)$now[0] - (float)$start[0];
return $deltasec + $deltamsec;
}
?>
</pre>
</body>
</html>