目次

Wikiエンジンにテーブル処理を搭載!

[ Category : CMS開発プロジェクト ] 2010年01月27日 23:43
 えらく長いコードになりつつありますが、どうにかテーブル(表)のHTML変換に成功しました。

現在の状況

コード

 今日もまずはコードからいってみます

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){
		/* DEBUG */	global $_debug;
		$result = "<table>\n";
		$end = count($buffer);
		for ($i=0; $i<$end; $i++){
			$line = $buffer[$i];
			$tr = $this->line2tr($line);
			$result .= '  <tr class="row'.$i.'">'."\n";
			$fin = count($tr);
			for ($g=0; $g<$fin; $g++){
				$result .= '    <'.$tr[$g]['type'].' class="'.$tr[$g]['class'].'"';
				if ($tr[$g]['colspan']){
					$result .= ' colspan="'.$tr[$g]['colspan'].'"';
				}
				if ($tr[$g]['rowspan']){
					$result .= ' rowspan="'.$tr[$g]['rowspan'].'"';
				}
				$result .= ">\n";
				$result .= '      '.$this->cording_p(array($tr[$g]['body']), FALSE)."\n";
				$result .= '    </'.$tr[$g]['type'].">\n";
			}
			$result .= "  </tr>\n";
		}
		$result .= "</table>\n";
		/* DEBUG */	if ($_debug) echo "[cording_table] table :\n";
		/* DEBUG */	if ($_debug) echo $result;
		return $result;
	}
 
	function line2tr($line){
		/* DEBUG */	global $_debug;
		$end = preg_match_all("/([\^\|][^\^\|]+)/", $line, $array);
		/* DEBUG */	if ($_debug) echo "[line2tr] array :\n";
		/* DEBUG */	if ($_debug) print_r($array);
		$type = array("^" => "th", "|" => "td");
		for ($i=0; $i<$end; $i++){
			if (preg_match("/^([\^\|])([ ]*)([^>_ ]*)([ ]*)$/", $array[0][$i], $td_raw[$i])){
				/* DEBUG */	if ($_debug) echo "[line2tr] A>td_raw[$i] :\n";
				/* DEBUG */	if ($_debug) print_r($td_raw[$i]);
				$td_type = $type[$td_raw[$i][1]];
				$td_colspan = FALSE;
				$td_rowspan = FALSE;
				$td_body = $td_raw[$i][3];
				if (strlen($td_raw[$i][2]) > 1 && strlen($td_raw[$i][4]) > 1){
					$td_class = "col".$i." centeralign";
				}else if (strlen($td_raw[$i][2]) > 1){
					$td_class = "col".$i." rightalign";
				}else if (strlen($td_raw[$i][4]) > 1){
					$td_class = "col".$i." leftalign";
				}else{
					$td_class = "col".$i;
				}
			}else if (preg_match("/([\^\|])>([0-9]*)([ ]*)([^>_ ]*)([ ]*)$/", $array[0][$i], $td_raw[$i])){
				/* DEBUG */	if ($_debug) echo "[line2tr] B>td_raw[$i] :\n";
				/* DEBUG */	if ($_debug) print_r($td_raw[$i]);
				$td_type = $type[$td_raw[$i][1]];
				$td_colspan = $td_raw[$i][2];
				$td_rowspan = FALSE;
				$td_body = $td_raw[$i][4];
				if (strlen($td_raw[$i][3]) > 1 && strlen($td_raw[$i][5]) > 1){
					$td_class = "col".$i." centeralign";
				}else if (strlen($td_raw[$i][3]) > 1){
					$td_class = "col".$i." rightalign";
				}else if (strlen($td_raw[$i][5]) > 1){
					$td_class = "col".$i." leftalign";
				}else{
					$td_class = "col".$i;
				}
			}else if (preg_match("/([\^\|])_([0-9]*)([ ]*)([^>_ ]*)([ ]*)$/", $array[0][$i], $td_raw[$i])){
				/* DEBUG */	if ($_debug) echo "[line2tr] C>td_raw[$i] :\n";
				/* DEBUG */	if ($_debug) print_r($td_raw[$i]);
				$td_type = $type[$td_raw[$i][1]];
				$td_colspan = FALSE;
				$td_rowspan = $td_raw[$i][2];
				$td_body = $td_raw[$i][4];
				if (strlen($td_raw[$i][3]) > 1 && strlen($td_raw[$i][5]) > 1){
					$td_class = "col".$i." centeralign";
				}else if (strlen($td_raw[$i][3]) > 1){
					$td_class = "col".$i." rightalign";
				}else if (strlen($td_raw[$i][5]) > 1){
					$td_class = "col".$i." leftalign";
				}else{
					$td_class = "col".$i;
				}
			}else if (preg_match("/([\^\|])>([0-9]*)_([0-9]*)([ ]*)([^>_ ]*)([ ]*)$/", $array[0][$i], $td_raw[$i])){
				/* DEBUG */	if ($_debug) echo "[line2tr] D>td_raw[$i] :\n";
				/* DEBUG */	if ($_debug) print_r($td_raw[$i]);
				$td_type = $type[$td_raw[$i][1]];
				$td_colspan = $td_raw[$i][2];
				$td_rowspan = $td_raw[$i][3];
				$td_body = $td_raw[$i][5];
				if (strlen($td_raw[$i][4]) > 1 && strlen($td_raw[$i][6]) > 1){
					$td_class = "col".$i." centeralign";
				}else if (strlen($td_raw[$i][4]) > 1){
					$td_class = "col".$i." rightalign";
				}else if (strlen($td_raw[$i][6]) > 1){
					$td_class = "col".$i." leftalign";
				}else{
					$td_class = "col".$i;
				}
			}
			/* DEBUG */	if ($_debug) echo "[line2tr] :\n";
			/* DEBUG */	if ($_debug) echo "type    =".$td_type."\n";
			/* DEBUG */	if ($_debug) echo "colspan =".$td_colspan."\n";
			/* DEBUG */	if ($_debug) echo "rowspan =".$td_rowspan."\n";
			/* DEBUG */	if ($_debug) echo "class   =".$td_class."\n";
			/* DEBUG */	if ($_debug) echo "body    =".$td_body."\n";
			$tr[$i] = array("type" => $td_type, "colspan" => $td_colspan, "rowspan" => $td_rowspan, "class" => $td_class, "body" => $td_body);
		}
		/* DEBUG */	if ($_debug) echo "[line2tr] tr :\n";
		/* DEBUG */	if ($_debug) print_r($tr);
		return $tr;
	}
 
	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";
		}
	}
 
}
 
?>

テーブルのWiki構文

 現在のところ、次のような構文にしようかと思っています。

^  ヘッダー  ^  ヘッダー  ^  ヘッダー  ^  ヘッダー  ^
|左                 |      中央       |                 右|_2 rowspan2|
|>2 colspan2                     |---------------|

 DokuWikiをベースに、colspanやrowspanまわりを変えました。

  1. colspanの指定 … 「|」もしくは「^」の直後に「>2」のように指定
    • 「>2」であれば「colspan = 2」
    • 「>3」であれば「colspan = 3」
  2. rowspanの指定 … 「|」もしくは「^」の直後に「_2」のように指定
    • 「_2」であれば「rowspan = 2」
    • 「_3」であれば「rowspan = 3」
  3. 複合表記
    • 「>2_3」→「colspan = 2, rowspan = 3」
    • 「_2>3」も可

※ 左寄せ、中央、右寄せの位置指定はDokuWikiと同じです

次はblockquote

 実は、blockquoteのWiki構文をどうしようか悩んでいます。DokuWiki方式でもいいんですが、何かいい案はないかな?

Discussion