目次

Wikiエンジン、大幅に改変

[ Category : CMS開発プロジェクト ] 2010年01月27日 03:42
 昨日のコードでは、どう考えてもテーブル処理を行うのに無理があったので、思い切って大幅に変更を加えました。

現在の状況

コード

 今日もコードから

cording.php
<?
class cording{
 
	function cording_p($buffer, $add_p=TRUE){
		global $a_target;
		$end = count($buffer);
		for ($i=0; $i<$end; $i++){
			$str = $buffer[$i];
			$str = preg_replace("/<([^\.=]*)>/", "&lt;$1&gt;", $str);
			$str = preg_replace("/[\\\]{2} +/", "<br />", $str);
			$str = preg_replace("/\*\*([^\*]*)\*\*/", "<b>$1</b>", $str);
			$str = preg_replace("/\/\/([^\/\[\]\{\}]*)\/\//", "<i>$1</i>", $str);
			$str = preg_replace("/__([^_]*)__/", "<u>$1</u>", $str);
			$str = preg_replace("/--([^-]*)--/", "<del>$1</del>", $str);
			$str = preg_replace("/\[\[http:\/\/([^\|\]]*)\|([^\]]*)\]\]/", '<a href="http://$1"'.$a_target.'>$2</a>', $str);
			$str = preg_replace("/\[\[http:\/\/([^\|\]]*)\]\]/", '<a href="http://$1"'.$a_target.'>$1</a>', $str);
			$str = preg_replace("/\{\{http:\/\/([^\|\}\? ]*)\}\}/", '<img src="http://$1" alt="$1" />', $str);
			$str = preg_replace("/\{\{http:\/\/([^\|\}\? ]*)\?([0-9]*)\}\}/", '<img src="http://$1" width="$2" alt="$1" />', $str);
			$str = preg_replace("/\{\{http:\/\/([^\|\}\? ]*)\?([0-9]*)x([0-9]*)\}\}/", '<img src="http://$1" width="$2" height="$3" alt="$1" />', $str);
			$str = preg_replace("/\{\{http:\/\/([^\|\}\? ]*) *\}\}/", '<img src="http://$1" alt="$1" class="img_left" align="left" />', $str);
			$str = preg_replace("/\{\{http:\/\/([^\|\}\? ]*)\?([0-9]*) *\}\}/", '<img src="http://$1" width="$2" alt="$1" class="img_left" align="left"/>', $str);
			$str = preg_replace("/\{\{http:\/\/([^\|\}\? ]*)\?([0-9]*)x([0-9]*) *\}\}/", '<img src="http://$1" width="$2" height="$3" alt="$1" class="img_left" align="left"/>', $str);
			$str = preg_replace("/\{\{ +http:\/\/([^\|\}\? ]*)\}\}/", '<img src="http://$1" alt="$1" class="img_right" align="rignt" />', $str);
			$str = preg_replace("/\{\{ +http:\/\/([^\|\}\? ]*)\?([0-9]*)\}\}/", '<img src="http://$1" width="$2" alt="$1" class="img_right" align="right" />', $str);
			$str = preg_replace("/\{\{ +http:\/\/([^\|\}\? ]*)\?([0-9]*)x([0-9]*)\}\}/", '<img src="http://$1" width="$2" height="$3" alt="$1" class="img_right" align="right" />', $str);
			$str = preg_replace("/\{\{ +http:\/\/([^\|\}\? ]*) +\}\}/", '<img src="http://$1" alt="$1" class="img_center" />', $str);
			$str = preg_replace("/\{\{ +http:\/\/([^\|\}\? ]*)\?([0-9]*) +\}\}/", '<img src="http://$1" width="$2" alt="$1" class="img_center" />', $str);
			$str = preg_replace("/\{\{ +http:\/\/([^\|\}\? ]*)\?([0-9]*)x([0-9]*) +\}\}/", '<img src="http://$1" width="$2" height="$3" alt="$1" class="img_center" />', $str);
			$str = preg_replace("/< ?\.([^\| ]*) ?\|([^>]*)>/", '<span class="$1">$2</span>', $str);
			$str = preg_replace("/< ?= ?([^\| ]*) ?\|([^>]*)>/", '<span style="$1">$2</span>', $str);
			if ($add_p){
				$result .= "<p>".$str."</p>\n";
			}else{
				$result .= $str;
			}
		}
		return $result;
	}
 
	function cording_div($buffer){
		$start_line = array_shift($buffer);
		if (preg_match("/^\#([^\.\#]*) ?\.([^\.\#\{]*)\{$/", $start_line, $data)){
			$result = '<div id="'.$data[1].'" class="'.$data[2].'">'."\n";
		}else if (preg_match("/^\.([^\.\#]*) ?\#([^\.\#\{]*)\{$/", $start_line, $data)){
			$result = '<div class="'.$data[1].'" id="'.$data[2].'">'."\n";
		}else if (preg_match("/^\.([^\.\#\{]*)\{$/", $start_line, $data)){
			$result = '<div class="'.$data[1].'">'."\n";
		}else if (preg_match("/^\#([^\.\#\{]*)\{$/", $start_line, $data)){
			$result = '<div id="'.$data[1].'">'."\n";
		}
		array_pop($buffer);
		$result .= $this->cording_p($buffer)."</div>\n";
		return $result;
	}
 
	function cording_table($buffer){}
 
	function cording_list($buffer){
		$end = count($buffer);
		for ($i=0; $i<$end; $i++){
			$line = $buffer[$i];
			if (preg_match("/^([ ]+)- ?(.*)$/", $line, $data)){
				$list[$i] = array('type' => 'ol', 'level' => floor(strlen($data[1])/2), 'body' => $data[2]);
			}else if (preg_match("/^([ ]+)\* ?(.*)$/", $line, $data)){
				$list[$i] = array('type' => 'ul', 'level' => floor(strlen($data[1])/2), 'body' => $data[2]);
			}
		}
		$line = $list[0];
		$last_type = $line['type'];
		$last_level = $line['level'];
		$open_tag = array($last_type);
		$result = "<".$last_type.' class="level_'.$last_level.'">'."\n".str_repeat(" ", ($last_level-1)*2+2).'<li class="level'.$last_level.'">'.$this->cording_p(array($line['body']), FALSE)."</li>\n";
		for ($i=1; $i<$end; $i++){
			$line = $list[$i];
			$now_type = $line['type'];
			$now_level = $line['level'];
			if ($now_level > $last_level){
				array_unshift($open_tag, $now_type);
				$result .= str_repeat(" ", ($last_level-1)*2+2)."<".$now_type.' class="level_'.$now_level.'">'."\n".str_repeat(" ", ($now_level-1)*2+2).'<li class="level'.$now_level.'">'.$this->cording_p(array($line['body']), FALSE)."</li>\n";
			}else if ($now_level < $last_level){
				array_shift($open_tag);
				$result .= str_repeat(" ", ($last_level-1)*2)."</".$last_type.">\n".str_repeat(" ", ($now_level-1)*2+2).'<li class="level'.$now_level.'">'.$this->cording_p(array($line['body']), FALSE)."</li>\n";
			}else{
				$result .= str_repeat(" ", ($now_level-1)*2+2).'<li class="level'.$now_level.'">'.$this->cording_p(array($line['body']), FALSE)."</li>\n";
			}
			$last_type = $now_type;
			$last_level = $now_level;
		}
		$end = count($open_tag);
		for ($i=0; $i<$end; $i++){
			$line = $open_tag[$i];
			$result .= str_repeat(" ", ($last_level-1)*2)."</".$line.">\n";
			$last_level --;
		}
		return $result;
	}
 
	function cording_blockquote($buffer){}
 
	function cording_code($buffer){}
 
	function cording_heading($buffer){
		$end = count($buffer);
		for ($i=0; $i<$end; $i++){
			$str = $buffer[$i];
			$str = preg_replace("/^===== ?([^\=]*)$/", "<h5>$1</h5>\n", $str);
			$str = preg_replace("/^==== ?([^\=]*)$/", "<h4>$1</h4>\n", $str);
			$str = preg_replace("/^=== ?([^\=]*)$/", "<h3>$1</h3>\n", $str);
			$str = preg_replace("/^== ?([^\=]*)$/", "<h2>$1</h2>\n", $str);
			$result .= $str;
		}
		return $result;
	}
 
	function get_type($line){
		$str1 = substr($line, 0, 1);
		$str2 = substr($line, 0, 2);
		$str3 = substr($line, 0, 3);
 
		static $mode_fix = FALSE;
		static $result;
 
		if ($line == ""){
			$result = "EOF";
		}else if (!$mode_fix){
			if ($str2 === "=="){
				$result = "cording_heading";
			}else if (preg_match("/^[\^\|]([^\^\|]*)[\^\|]/",$line)){
				$result = "cording_table";
			}else if (preg_match("/^ +[\*-](.*)/", $line)){
				$result = "cording_list";
			}else if (preg_match("/^<code ?(.*)>$/", $line)){
				$result = "cording_code";
				$mode_fix = TRUE;
			}else if (preg_match("/^[\.\#]([^\{]*)\{$/", $line)){
				$result = "cording_div";
				$mode_fix = TRUE;
			}else if ($line === "}"){
				$result = "cording_div";
			}else{
				$result = "cording_p";
			}
		}else if (($result === "cording_code" && $line === '</code>') || ($result === "cording_div" && $line === "}")){
			$mode_fix = FALSE;
		}
		return $result;
	}
 
	function is_buffer($current_line, $follow_line){
		global $_cording;
		$result = FALSE;
		if (($_cording = $this->get_type($current_line)) == $this->get_type($follow_line)){
			$result = TRUE;
		}
		return $result;
	}
 
	function cording_start($text){
		global $_cording;
		$corded = array();
		$buffer = array();
		$before_cording = preg_split("/[\r\n]/", $text, -1, PREG_SPLIT_NO_EMPTY);
		$end = count($before_cording);
		for ($i=0; $i<$end; $i++){
			$current_line = $before_cording[$i];
			$follow_line = $before_cording[$i+1];
			array_push ($buffer, $current_line);
			if (!$this->is_buffer($current_line, $follow_line)){
				array_push ($corded, $this->$_cording($buffer));
				$buffer = array();
			}
		}
		$this->cording_finish($corded);
	}
 
	function cording_finish($corded = array()){
		while ($line = array_shift($corded)){
			echo $line."\n";
		}
	}
 
}
 
?>

どう変えた? なぜ変えた??

 昨日のコードでは、テキストを1行ずつ順にHTML変換していましたが、ある程度のブロックごとに区切り、まとめてHTML変換するように変えました。これは、テーブルの処理を次の「テーブル処理案」ような流れで行おうと考えているからです。

 cording_table()に1行ずつ値を渡し、1行ずつHTML変換させていたのでは、テーブルデータ全体を見渡すことができません。先が見えない状態で1行ずつ処理させるよりも、いったん全てのデータを配列に整頓してしまい、それから一気にHTML変換した方がやりやすいような気がしますし、何より「rowspanに対応」させることも可能になります。

 そういうわけで、「いまは何を変換しようとしているのか」をチェックし、変換しようとしているタイプ1)が同じ間は$bufferにためておき、タイプが変わった瞬間に該当するメソッドに$bufferを渡すように変えたわけです。

テーブル処理案

1. テーブル箇所を$bufferにまとめてcording_table()に渡す

$buffer = array(
  [1] => "^  row-1 col-1  ^  row-1 col-2  ^  row-1 col-3  ^  row-1 col-4  ^",
  [2] => "|  row-2 col-1  |  row-2 col-2  |  row-2 col-3  |  row-2 col-4  |",
  [3] => "|  row-3 col-1  |  row-3 col-2  |  row-3 col-3  |  row-3 col-4  |")

2. cording_table()内で$bufferを次のように変換する

$table = array(
    "row-1" => array(
        "col-1"  => array(
            "type" => "th",
            "class" => "centeralign",
            "colspan" => "0",
            "rowspan" => "0",
            "body" => "row-1 col-1"),
        "col-2" => array(
            "type" => "th",
            "class" => "centeralign",
            "colspan" => "0",
            "rowspan" => "0",
            "body" => "row-1 col-2"),
        "col-3" => array( ...... ),
        "col-4" => array( ...... )),
    "row-2" => array(
        "col-1" => ... 以下略

3. HTMLに変換する

 (ココ考え中)

Discussion

1) 現在はdiv, p, table, list, heading, blockquote, codeの7種。まだ増える可能性アリ。