从线性数组创建一个 PHP 的多维数组
Create a multi-dimensional array with PHP from lineal array
TL;DR 我正在寻找一个函数来从 PHP 中的一维数组创建嵌套 <ol>
列表。
1) 目前我的测试页中有这个简化的标记:
<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>
2) 然后通过一个非常简单的函数将其捕获到一个一维数组中,如下所示:
array
(
0 => "H2 Spiders",
1 => "H2 Beetles",
2 => "H3 External morphology",
3 => "H4 Head",
4 => "H4 Thorax",
5 => "H4 Legs",
6 => "H3 Anatomy and physiology"
7 => "H2 Ants"
);
3) 这是棘手的部分,因为我使用带有这些过于复杂的 if 语句的 next 循环来填充多维数组。
$toc = array ();
//
foreach ($array as $value) {
$value_arr = explode(' ', $value, 2);
$depth = str_replace("H", "", $value_arr[0]);
$content = $value_arr[1];
//
if ($depth == 1) $toc[$title] = null;
elseif ($depth == 2) {
if (empty (end ($toc))) $toc[array_key_last ($toc)] = array ($title => null);
else $toc[array_key_last ($toc)][$title] = null;
} elseif ($depth == 3) {
if (empty (end ($toc[array_key_last ($toc)]))) $toc[array_key_last ($toc)][array_key_last ($toc[array_key_last ($toc)])] = array ($title => null);
else $toc[array_key_last ($toc)][array_key_last ($toc[array_key_last ($toc)])][$title] = '';
}
}
输出:
Array (
[Spiders] =>
[Beetles] => Array
(
[External morphology] => Array
(
[Head] =>
[Thorax] =>
[Legs] =>
)
[Anatomy and physiology] =>
)
[Ants] =>
)
4) 最后用这个函数解析成一个完美缩进的 html 列表。
function table_of_contents ($toc, $output = '') {
foreach ($toc as $key => $value) {
$output = "$output <li><a href='#@" . sanitize_title ($key) . "'>$key</a>" . (is_array ($value) ? table_of_contents ($value) : null) . '</li>';
}
//
return "<ol>$output</ol>";
}
//
table_of_contents ($toc);
-
- 蜘蛛
- 甲虫
- 外部形态
- 头部
- 胸部
- 腿部
- 解剖学和生理学
- 蚂蚁
第一步、第二步和第四步一切正常,但我目前的方法有一个缺点,即在第三步中只允许我从第一个数组开始最多三个级别的深度。
我的问题是是否有更有效、更简洁的方法来创建具有(可能)递归函数或类似函数的多维数组?
使用 preg_match_all
可能更容易解析您的输入;这可以为您提供深度数组和相关值。然后你可以遍历这些数组,当深度增加时打开一个 <ol>
,当深度减小时关闭它:
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
preg_match_all('/<h(\d)>([^<]+)/', $html, $matches);
$cdepth = $matches[1][0] - 1;
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "</li>\n";
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol>
<li><a href="Spiders">Spiders</a></li>
<li><a href="Beetles">Beetles</a>
<ol>
<li><a href="External morphology">External morphology</a>
<ol>
<li><a href="Head">Head</a></li>
<li><a href="Thorax">Thorax</a></li>
<li><a href="Legs">Legs</a></li>
</ol>
</li>
<li><a href="Anatomy and physiology">Anatomy and physiology</a></li>
</ol>
</li>
<li><a href="Ants">Ants</a></li>
</ol>
更新
如果出于输出以外的其他原因需要第三阶段数组,可以使用此递归函数生成它(它仍然适用于 preg_match_all
的输出):
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h5>Feet</h5>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
function push_values(&$k, $depth, $content) {
$output = array();
$cdepth = $depth[$k];
while ($k < count($depth)) {
if ($depth[$k] == $cdepth) {
$output[$content[$k]] = '';
$k++;
}
elseif ($depth[$k] > $cdepth) {
$output[$content[$k-1]] = push_values($k, $depth, $content);
}
else {
return $output;
}
}
return $output;
}
preg_match_all('/<h(\d)>([^<]+)/', $html, $matches);
$key = 0;
print_r(push_values($key, $matches[1], $matches[2]));
输出:
Array
(
[Spiders] =>
[Beetles] => Array
(
[External morphology] => Array
(
[Head] =>
[Thorax] =>
[Legs] => Array
(
[Feet] =>
)
)
[Anatomy and physiology] =>
)
[Ants] =>
)
最后,我建议对@Nick 发布的第一个代码进行小的修复,该代码会在下一个场景中导致不希望的 HTML 输出,其中深度差异大于 2 将改变最表面的兄弟姐妹;例如,<h6>
之后的 <h3>
变为 <h5>
并且下一个 <h2>
被解析为 <h4>
:
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h5>Feet</h5>
<h6>Toes</h6>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "</li>\n";
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol>
<li><a href="Spiders">Spiders</a></li>
<li><a href="Beetles">Beetles</a>
<ol>
<li><a href="External morphology">External morphology</a>
<ol>
<li><a href="Head">Head</a></li>
<li><a href="Thorax">Thorax</a></li>
<li><a href="Legs">Legs</a>
<ol>
<li><a href="Feet">Feet</a>
<ol>
<li><a href="Toes">Toes</a></li>
</ol>
</li>
<li><a href="Anatomy and physiology">Anatomy and physiology</a></li>
</ol>
</li>
<li><a href="Ants">Ants</a></li>
</ol>
</li></ol></li></ol>
-
为了解决这个问题,我刚刚添加了另一个 while 语句以在添加下一个 <li>
元素之前放置正确数量的 </li></ol>
,现在可以正确验证 W3C 检查器。
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
while ($cdepth -- > $depth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "\n";
}
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol>
<li><a href="Spiders">Spiders</a></li>
<li><a href="Beetles">Beetles</a>
<ol>
<li><a href="External morphology">External morphology</a>
<ol>
<li><a href="Head">Head</a></li>
<li><a href="Thorax">Thorax</a></li>
<li><a href="Legs">Legs</a>
<ol>
<li><a href="Feet">Feet</a>
<ol>
<li><a href="Toes">Toes</a></li>
</ol>
</li>
</ol>
</li>
</ol>
<li><a href="Anatomy and physiology">Anatomy and physiology</a></li>
</ol>
<li><a href="Ants">Ants</a></li>
</ol>
TL;DR 我正在寻找一个函数来从 PHP 中的一维数组创建嵌套 <ol>
列表。
1) 目前我的测试页中有这个简化的标记:
<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>
2) 然后通过一个非常简单的函数将其捕获到一个一维数组中,如下所示:
array
(
0 => "H2 Spiders",
1 => "H2 Beetles",
2 => "H3 External morphology",
3 => "H4 Head",
4 => "H4 Thorax",
5 => "H4 Legs",
6 => "H3 Anatomy and physiology"
7 => "H2 Ants"
);
3) 这是棘手的部分,因为我使用带有这些过于复杂的 if 语句的 next 循环来填充多维数组。
$toc = array ();
//
foreach ($array as $value) {
$value_arr = explode(' ', $value, 2);
$depth = str_replace("H", "", $value_arr[0]);
$content = $value_arr[1];
//
if ($depth == 1) $toc[$title] = null;
elseif ($depth == 2) {
if (empty (end ($toc))) $toc[array_key_last ($toc)] = array ($title => null);
else $toc[array_key_last ($toc)][$title] = null;
} elseif ($depth == 3) {
if (empty (end ($toc[array_key_last ($toc)]))) $toc[array_key_last ($toc)][array_key_last ($toc[array_key_last ($toc)])] = array ($title => null);
else $toc[array_key_last ($toc)][array_key_last ($toc[array_key_last ($toc)])][$title] = '';
}
}
输出:
Array (
[Spiders] =>
[Beetles] => Array
(
[External morphology] => Array
(
[Head] =>
[Thorax] =>
[Legs] =>
)
[Anatomy and physiology] =>
)
[Ants] =>
)
4) 最后用这个函数解析成一个完美缩进的 html 列表。
function table_of_contents ($toc, $output = '') {
foreach ($toc as $key => $value) {
$output = "$output <li><a href='#@" . sanitize_title ($key) . "'>$key</a>" . (is_array ($value) ? table_of_contents ($value) : null) . '</li>';
}
//
return "<ol>$output</ol>";
}
//
table_of_contents ($toc);
-
- 蜘蛛
- 甲虫
- 外部形态
- 头部
- 胸部
- 腿部
- 解剖学和生理学
- 外部形态
- 蚂蚁
第一步、第二步和第四步一切正常,但我目前的方法有一个缺点,即在第三步中只允许我从第一个数组开始最多三个级别的深度。
我的问题是是否有更有效、更简洁的方法来创建具有(可能)递归函数或类似函数的多维数组?
使用 preg_match_all
可能更容易解析您的输入;这可以为您提供深度数组和相关值。然后你可以遍历这些数组,当深度增加时打开一个 <ol>
,当深度减小时关闭它:
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
preg_match_all('/<h(\d)>([^<]+)/', $html, $matches);
$cdepth = $matches[1][0] - 1;
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "</li>\n";
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol>
<li><a href="Spiders">Spiders</a></li>
<li><a href="Beetles">Beetles</a>
<ol>
<li><a href="External morphology">External morphology</a>
<ol>
<li><a href="Head">Head</a></li>
<li><a href="Thorax">Thorax</a></li>
<li><a href="Legs">Legs</a></li>
</ol>
</li>
<li><a href="Anatomy and physiology">Anatomy and physiology</a></li>
</ol>
</li>
<li><a href="Ants">Ants</a></li>
</ol>
更新
如果出于输出以外的其他原因需要第三阶段数组,可以使用此递归函数生成它(它仍然适用于 preg_match_all
的输出):
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h5>Feet</h5>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
function push_values(&$k, $depth, $content) {
$output = array();
$cdepth = $depth[$k];
while ($k < count($depth)) {
if ($depth[$k] == $cdepth) {
$output[$content[$k]] = '';
$k++;
}
elseif ($depth[$k] > $cdepth) {
$output[$content[$k-1]] = push_values($k, $depth, $content);
}
else {
return $output;
}
}
return $output;
}
preg_match_all('/<h(\d)>([^<]+)/', $html, $matches);
$key = 0;
print_r(push_values($key, $matches[1], $matches[2]));
输出:
Array
(
[Spiders] =>
[Beetles] => Array
(
[External morphology] => Array
(
[Head] =>
[Thorax] =>
[Legs] => Array
(
[Feet] =>
)
)
[Anatomy and physiology] =>
)
[Ants] =>
)
最后,我建议对@Nick 发布的第一个代码进行小的修复,该代码会在下一个场景中导致不希望的 HTML 输出,其中深度差异大于 2 将改变最表面的兄弟姐妹;例如,<h6>
之后的 <h3>
变为 <h5>
并且下一个 <h2>
被解析为 <h4>
:
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h5>Feet</h5>
<h6>Toes</h6>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "</li>\n";
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol>
<li><a href="Spiders">Spiders</a></li>
<li><a href="Beetles">Beetles</a>
<ol>
<li><a href="External morphology">External morphology</a>
<ol>
<li><a href="Head">Head</a></li>
<li><a href="Thorax">Thorax</a></li>
<li><a href="Legs">Legs</a>
<ol>
<li><a href="Feet">Feet</a>
<ol>
<li><a href="Toes">Toes</a></li>
</ol>
</li>
<li><a href="Anatomy and physiology">Anatomy and physiology</a></li>
</ol>
</li>
<li><a href="Ants">Ants</a></li>
</ol>
</li></ol></li></ol>
-
为了解决这个问题,我刚刚添加了另一个 while 语句以在添加下一个 <li>
元素之前放置正确数量的 </li></ol>
,现在可以正确验证 W3C 检查器。
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
while ($cdepth -- > $depth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "\n";
}
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol>
<li><a href="Spiders">Spiders</a></li>
<li><a href="Beetles">Beetles</a>
<ol>
<li><a href="External morphology">External morphology</a>
<ol>
<li><a href="Head">Head</a></li>
<li><a href="Thorax">Thorax</a></li>
<li><a href="Legs">Legs</a>
<ol>
<li><a href="Feet">Feet</a>
<ol>
<li><a href="Toes">Toes</a></li>
</ol>
</li>
</ol>
</li>
</ol>
<li><a href="Anatomy and physiology">Anatomy and physiology</a></li>
</ol>
<li><a href="Ants">Ants</a></li>
</ol>