I Love China

技术·人生

技术服务生活
繁體
10月 22nd, 2007

[php]php做ActionScript的语法高亮

php使用php处理ActionScript代码,生成语法高亮的HTML页面。
处理的关键其实是注释段代码和引号里的代码。其他部分只要用正则表达式替换就可以了。
字符串代码和注释代码都具有很高的处理等级,因为注释里的任何代码,包括关键字、语法字,字符串等,都不会再处理,统一当作注释格式显示。而字符串里的代码也是这样,字符串里的任何代码,包括符合注释规则的代码都不应该再处理,而统一成字符串格式输出。
为此,我们需要首先把注释和字符串单独提取出来,保存在两个数组里面,然后对剩余的,不包含注释和字符串的代码进行语法高亮处理,最后,再把注释和字符串替换回去就可以了。
在做任何事情之前,先把特殊字符替换成HTML字符:
PHP Code

function filterHTML($asCode)
{
	$replace = array ("&",
					""",
					"'",
					"<",
					">",
					" ");                  

	$search = array ("'&'",
					"'\"'",
					"'\''",
					"'< '",
					"'>'",
					"' '");

	$asCode = preg_replace ($search, $replace, $asCode);
	return $asCode;

}

注意:$search数组里第2,3个元素第一个单引号后是有转义符的,但是由于wordpress处理的时候把转义符给去掉了,所以没显示出来。
在提取注释和字符串的时候应该注意的是,注释和字符串有同等的权利,只能按照谁出现的早就处理谁的规则进行提取,而不能说是先提取注释,或者先提取字符串,因为存在注释中包含字符串,字符串中包含注释的情况。为此,我们需要使用strpos就行判断。另外,注释有两种格式,一种是//,另一个是/**/,字符串包括双引号的和单引号的。因此首先要分别使用strpos获得第一次出现它们的位置,然后获取值最小的那个,也就是最早出现的那个,进行处理。直到再也查不到任何符合规则的代码,或者中间遇到了错误。

首先,我们建立两个数组,保存提取出来的代码
PHP Code

$comment = array();
$quot = array();
$newline = chr(13).chr(10);

一个保存注释代码,一个保存字符串代码,然后获取第一次出现注释和字符串的位置。有一点需要注意,获得引号位置时,有可能遇到的一种情况是在引号前有转义符,这是的引号不是我们要找的引号,为此,专门写一个函数获取字符的位置
PHP Code

// 查找下一个引号
function getNextQuot($asCode,$str,$start)
{
	$p1 = strpos($asCode, $str, $start);
	$p2 = strpos($asCode, '\\\\'.$str,$start);
	$p3 = strpos($asCode, '\\\\\\\\'.$str,$start);
	if($p2 === false || $p2 +1 !== $p1 || $p3 + 1 === $p2)
	{

		return $p1;
	}
	return getNextQuot($asCode, $str, $p1 + 1);
}

PHP Code

$c1pos = strpos( $asCode,	'//');
$c2pos = strpos( $asCode,	'/*');
$q1pos = getNextQuot($asCode,	'&#34;',0);
$q2pos = getNextQuot( $asCode,	"&#39;",0);

然后就要获取它们中值最小的那个,找到后就替换字符串,然后在重复这个动作,直到代码中不再有注释和字符串,因此,我们需要把它们写到一个循环里,这里使用while循环,跳出的条件就是注释和字符串的位置都不是false.
PHP Code

while($c1pos !== false || $c2pos !== false || $q1pos !== false || $q2pos !== false)

注意,这里判断使用的是 !==,因为使用strpos的返回值可能是false,也可能是个数值,但数值中又包括0,所以不能使用!=判断。
下一步就是要找到值最小的那个数,这里我使用的方法是先保存到数组里,然后对数组排序
PHP Code

$sortAry = array();
if($c1pos !== false)
{
	$sortAry['c1'= $c1pos;
}
if($c2pos !== false)
{
	$sortAry['c2'= $c2pos;
}
if($q1pos !== false)
{
	$sortAry['q1'= $q1pos;
}
if($q2pos !== false)
{
	$sortAry['q2'= $q2pos;
}
// 交换键/值
$sortAry = array_flip($sortAry);
ksort($sortAry,SORT_NUMERIC);

注意,这里是交换键值后进行的排序,目的是获得键名,然后才能知道应该处理注释还是字符串。
下面就是要根据索引0处的值分别处理,这里使用switch语句
PHP Code

$nq = 0;
$qstart = 0;
$ff = '';
$offset = 0;
switch(array_shift ($sortAry))
{
	case 'c1':
		$nq = strpos($asCode,$newline,$c1pos);
		if($nq === false)
		{
			$nq = strlen($asCode);
		}
		$qstart = $c1pos;
		$ff = 'as_cm';
		$offset = 0;
		$ctrlAry = & $comment;
		break;
	case 'c2':
		$nq = strpos($asCode, '*/', $c2pos + 1);
		$qstart = $c2pos;
		$ff = 'as_cm';
		$offset = 2;
		$ctrlAry = & $comment;
		break;
	case 'q1':
		$nq = getNextQuot($asCode, '&#34;', $q1pos + 1);
		$qstart = $q1pos;
		$ff = 'as_qt';
		$offset = 5;
		$ctrlAry = & $quot;
		break;
	case 'q2':
		$nq = getNextQuot($asCode, "&#39;", $q2pos + 1);
		$qstart = $q2pos;
		$ff = 'as_qt';
		$offset = 5;
		$ctrlAry = & $quot;
		break;
}

四种情况的处理代码基本类似,都是要获得它的结束位置,对于注释,需要获得注释的结束位置,比如是行尾或者是*/出现的地方,字符串就是要获得单引号或双引号出现的地方,需要注意的是,我们这里使用strpos时指定了它的第3个参数,也就是要指定搜索的起始位置。另外一个注意的地方是针对情况c1的稍微不同,因为c1对应的情况是注释//的代码,它的规则只是到行尾,如果行尾有换行符,那么首先找换行符,如果没有换行符,则认为是代码到了尽头了,所以取字符串的长度。
再接下来,就是要提取字符串了,
PHP Code

if($nq !== false)
{
	$qCount = count($ctrlAry) + 1;
	$ctrlAry[$ff.$qCount] = substr($asCode,$qstart,$nq - $qstart + $offset);
	$asCode = substr($asCode,0,$qstart) . '['.$ff .$qCount . ']'.substr($asCode,$nq+$offset);
}
else
{
	break;
}

这里保存到数组中的键名是按顺序用下排的,为了方便后面替换。
接下来就是为下次循环做准备
PHP Code

$c1pos = strpos( $asCode,	'//');
$c2pos = strpos( $asCode,	'/*');
$q1pos = getNextQuot($asCode,	'&#34;',0);
$q2pos = getNextQuot( $asCode,	"&#39;",0);

OK,到此,注释和字符串都提取出来了,就可以对剩余代码进行关键字处理了。这一步省略了,无非就是用正则表达式替换。
最后,我们要把注释和字符串替换回来
PHP Code

// 替换引号
while(list($key,$val) = each($quot))
{
	$asCode = str_replace('['.$key.']','<span class="fms_quot">'.$val.'</span>',$asCode);
}
// 替换注释
while(list($key,$val) = each($comment))
{
	$asCode = str_replace('['.$key.']','<span class="fms_comment">'.$val.'</span>',$asCode);
}

然后就是写好样式表就可以了。
这里提供一个效果供参考
点击这里查看示例效果

随机文章:

Leave a Reply