[php]php做ActionScript的语法高亮
使用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, '"',0); $q2pos = getNextQuot( $asCode, "'",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, '"', $q1pos + 1); $qstart = $q1pos; $ff = 'as_qt'; $offset = 5; $ctrlAry = & $quot; break; case 'q2': $nq = getNextQuot($asCode, "'", $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, '"',0); $q2pos = getNextQuot( $asCode, "'",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