記述方法は、
1. 通常のリストは「-」、番号付きリストは「+」を行頭に付ける
2. 更に行頭に1つ以上の半角スペースを付けると、入れ子構造になる(入れ子の階層に制限なし)
となり、問題なく動作させるにはどうしたらよいでしょうか?
できればソース付きで回答して頂くと大変助かります。
よろしくお願いします。
■入力テキスト
-リスト1
-リスト2
+番号付きリスト2-A
+番号付きリスト2-B
-リスト3-A
-リスト3-B
+番号付きリスト2-C
-リスト3
■出力結果
<ul>
<li>リスト1</li>
<li>リスト2
<ol>
<li>番号付きリスト2-A</li>
<li>番号付きリスト2-B
<ul>
<li>リスト3-A</li>
<li>リスト3-B</li>
</ul>
</li>
<li>番号付きリスト2-C</li>
</ol>
</li>
<li>リスト3</li>
</ul>
<?php $input = <<< ENDOFINPUT -リスト1 -リスト2 +番号付きリスト2-A +番号付きリスト2-B -リスト3-A -リスト3-B +番号付きリスト2-C -リスト3 ENDOFINPUT; $lines = preg_split('/[\r\n]+/', $input) ; // リストのタグを全て閉じる function close_lists($d) { while ($l = array_pop($d)) { echo "</li>\n". str_repeat(' ', count($d)*4). // インデント調整 ($l[1] == '-' ? '</ul>' : '</ol>') ; } echo "\n" ; return array() ; } $d = array() ; // 現在の階層を保存 while ($l = array_shift($lines)) { if (preg_match('/^( *)([-+])(.*)$/', $l, $m)) { $e = end($d) ; // 現在の階層 // インデントが浅いか種類が変わればタグを閉じる while ($d && ($e[0] > $m[1] || ($e[0] == $m[1] && $e[1] != $m[2]))) { array_pop($d) ; echo "</li>\n". str_repeat(' ', count($d)*4). // インデント調整 ($e[1] == '-' ? '</ul>' : '</ol>') ; $e = end($d) ; } // 階層を増やす if (!count($d) || $e[0] < $m[1]) { $d[] = array($m[1], $m[2]) ; if ($e) echo "\n" ; echo str_repeat(' ', (count($d)-1)*4). // インデント調整 ($m[2] == '-' ? '<ul>' : '<ol>')."\n" ; } else echo "</li>\n" ; // リストの要素 echo str_repeat(' ', count($d)*4-2). // インデント調整 '<li>'.$m[3] ; } // リストの記号がない else { $d = close_lists($d) ; echo "$l\n" ; } } close_lists($d) ; ?>
出力例
<ul> <li>リスト1</li> <li>リスト2 <ol> <li>番号付きリスト2-A</li> <li>番号付きリスト2-B <ul> <li>リスト3-A</li> <li>リスト3-B</li> </ul></li> <li>番号付きリスト2-C</li> </ol></li> <li>リスト3</li> </ul>
どの行にも + か - があるものという前提です。
<?php mb_internal_encoding('utf-8'); $text =<<< EOT -リスト1 -リスト2 +番号付きリスト2-A +番号付きリスト2-B -リスト3-A -リスト3-B +番号付きリスト2-C -リスト3 EOT; function text2list($text) { $data = explode("\n", $text); $n = count($data); $output = ''; $level = -1; for ($i = 0; $i < $n; $i++) { $pos = strpos($data[$i], '+'); if ($pos == FALSE) { $pos = strpos($data[$i], '-'); } if ($pos < $level) { for ($j = $level; $j > $pos; $j--) { $output .= '</' . $tag[$level] . ">\n"; } $output .= '<li>' . substr($data[$i], $pos + 1) . "</li>\n"; $level = $pos; } else if ($pos > $level) { $ch = substr($data[$i], $pos, 1); if ($ch == '+') $c = 'ol'; else $c = 'ul'; for ($j = $level + 1; $j <= $pos; $j++) { $tag[$j] = $c; $output .= '<' . $tag[$j] . ">\n"; } $output .= '<li>' . substr($data[$i], $pos + 1) . "</li>\n"; $level = $pos; } else if ($data[$i] == '') { $output .= '</' . $tag[0] . ">\n"; } else { $output .= '<li>' . substr($data[$i], $pos + 1) . "</li>\n"; } } return $output; } $output = text2list($text); echo $output; ?>
遅れましたが、回答有り難うございました。
参考にして色々試したいと思います。
<?php $input = <<< ENDOFINPUT -リスト1 -リスト2 +番号付きリスト2-A +番号付きリスト2-B -リスト3-A -リスト3-B +番号付きリスト2-C -リスト3 ENDOFINPUT; $lines = preg_split('/[\r\n]+/', $input) ; // リストのタグを全て閉じる function close_lists($d) { while ($l = array_pop($d)) { echo "</li>\n". str_repeat(' ', count($d)*4). // インデント調整 ($l[1] == '-' ? '</ul>' : '</ol>') ; } echo "\n" ; return array() ; } $d = array() ; // 現在の階層を保存 while ($l = array_shift($lines)) { if (preg_match('/^( *)([-+])(.*)$/', $l, $m)) { $e = end($d) ; // 現在の階層 // インデントが浅いか種類が変わればタグを閉じる while ($d && ($e[0] > $m[1] || ($e[0] == $m[1] && $e[1] != $m[2]))) { array_pop($d) ; echo "</li>\n". str_repeat(' ', count($d)*4). // インデント調整 ($e[1] == '-' ? '</ul>' : '</ol>') ; $e = end($d) ; } // 階層を増やす if (!count($d) || $e[0] < $m[1]) { $d[] = array($m[1], $m[2]) ; if ($e) echo "\n" ; echo str_repeat(' ', (count($d)-1)*4). // インデント調整 ($m[2] == '-' ? '<ul>' : '<ol>')."\n" ; } else echo "</li>\n" ; // リストの要素 echo str_repeat(' ', count($d)*4-2). // インデント調整 '<li>'.$m[3] ; } // リストの記号がない else { $d = close_lists($d) ; echo "$l\n" ; } } close_lists($d) ; ?>
出力例
<ul> <li>リスト1</li> <li>リスト2 <ol> <li>番号付きリスト2-A</li> <li>番号付きリスト2-B <ul> <li>リスト3-A</li> <li>リスト3-B</li> </ul></li> <li>番号付きリスト2-C</li> </ol></li> <li>リスト3</li> </ul>
遅れましたが、シンプルな実装でとても勉強になります。
こんなやり方があったとは。回答どうも有り難うございました。
遅れましたが、シンプルな実装でとても勉強になります。
2013/04/30 07:46:56こんなやり方があったとは。回答どうも有り難うございました。