Page 1 of 1

highlighting logic needs improvement

Posted: Wed Jun 07, 2006 10:51 pm
by logikal2
Hey guys,

I'm new to these forums, and fairly new to PHP, so I thought maybe you all could give me a little advice to help me with this problem. I just created an actionscript syntax highlighter for this wiki i'm creating, but it's taking too long for PHP to process all the data sometimes. For example, it takes around 20 seconds to process about 1,000 lines of actionscript code.

I think the problem is that I'm searching through the entire list way too many times, but who knows. Here's what I have so far: (don't be intimidated, the first half of the code are just the KEYWORDS)

* the only variable that needs to be passed into the following function (parse_code) is $out, which is an example Actionscript string*

Inside the CSS file:
.kw1 {color:#ff6600;}
.w6c {color:#808080;}
.w6r {color:#ff0000;}
.w6n {color:#cc66cc;}
.w6s {color:#66cc66;}

PHP:

Code: Select all

<?php
function parse_code($out) {
	$as=array(
		'KEYWORDS'=>array(
			1=>array(
				'#include','for','foreach','if','elseif','else','while','do','dowhile',
				'endwhile','endif','switch','case','endswitch','return','break','continue','in'
			),
			2=>array('null','false','true','var','default','function','class','new','_global'),
			3=>array(
				'#endinitclip','#initclip','__proto__','_accProps','_alpha','_currentframe',
				'_droptarget','_focusrect','_framesloaded','_height','_highquality','_lockroot',
				'_name','_parent','_quality','_root','_rotation','_soundbuftime','_target','_totalframes',
				'_url','_visible','_width','_x','_xmouse','_xscale','_y','_ymouse','_yscale','abs',
				'Accessibility','acos','activityLevel','add','addListener','addPage','addProperty',
				'addRequestHeader','align','allowDomain','allowInsecureDomain','and','appendChild',
				'apply','Arguments','Array','asfunction','asin','atan','atan2','attachAudio','attachMovie',
				'attachSound','attachVideo','attributes','autosize','avHardwareDisable','background',
				'backgroundColor','BACKSPACE','bandwidth','beginFill','beginGradientFill','blockIndent',
				'bold','Boolean','border','borderColor','bottomScroll','bufferLength','bufferTime',
				'builtInItems','bullet','Button','bytesLoaded','bytesTotal','call','callee','caller',
				'Camera','capabilities','CAPSLOCK','caption','catch','ceil','charAt','charCodeAt',
				'childNodes','chr','clear','clearInterval','cloneNode','close','Color','concat',
				'connect','condenseWhite','constructor','contentType','ContextMenu','ContextMenuItem',
				'CONTROL','copy','cos','createElement','createEmptyMovieClip','createTextField',
				'createTextNode','currentFps','curveTo','CustomActions','customItems','data','Date',
				'deblocking','delete','DELETEKEY','docTypeDecl','domain','DOWN',
				'duplicateMovieClip','duration','dynamic','E','embedFonts','enabled',
				'END','endFill','ENTER','eq','Error','ESCAPE','escape','eval',
				'exactSettings','exp','extends','finally','findText','firstChild','floor',
				'flush','focusEnabled','font','fps','fromCharCode','fscommand',
				'gain','ge','get','getAscii','getBeginIndex','getBounds','getBytesLoaded','getBytesTotal',
				'getCaretIndex','getCode','getCount','getDate','getDay','getDepth','getEndIndex','getFocus',
				'getFontList','getFullYear','getHours','getInstanceAtDepth','getLocal','getMilliseconds',
				'getMinutes','getMonth','getNewTextFormat','getNextHighestDepth','getPan','getProgress',
				'getProperty','getRGB','getSeconds','getSelected','getSelectedText','getSize','getStyle',
				'getStyleNames','getSWFVersion','getText','getTextExtent','getTextFormat','getTextSnapshot',
				'getTime','getTimer','getTimezoneOffset','getTransform','getURL','getUTCDate','getUTCDay',
				'getUTCFullYear','getUTCHours','getUTCMilliseconds','getUTCMinutes','getUTCMonth','getUTCSeconds',
				'getVersion','getVolume','getYear','globalToLocal','goto','gotoAndPlay','gotoAndStop',
				'hasAccessibility','hasAudio','hasAudioEncoder','hasChildNodes','hasEmbeddedVideo','hasMP3',
				'hasPrinting','hasScreenBroadcast','hasScreenPlayback','hasStreamingAudio','hasStreamingVideo',
				'hasVideoEncoder','height','hide','hideBuiltInItems','hitArea','hitTest','hitTestTextNearPos',
				'HOME','hscroll','html','htmlText','ID3','ifFrameLoaded','ignoreWhite','implements',
				'import','indent','index','indexOf','Infinity','-Infinity','INSERT','insertBefore','install',
				'instanceof','int','interface','isActive','isDebugger','isDown','isFinite','isNaN','isToggled',
				'italic','join','Key','language','lastChild','lastIndexOf','le','leading','LEFT','leftMargin',
				'length','level','lineStyle','lineTo','list','LN10','LN2','load','loadClip','loaded','loadMovie',
				'loadMovieNum','loadSound','loadVariables','loadVariablesNum','LoadVars','LocalConnection',
				'localFileReadDisable','localToGlobal','log','LOG10E','LOG2E','manufacturer','Math','max',
				'MAX_VALUE','maxChars','maxhscroll','maxscroll','mbchr','mblength','mbord','mbsubstring','menu',
				'message','Microphone','min','MIN_VALUE','MMExecute','motionLevel','motionTimeOut','Mouse',
				'mouseWheelEnabled','moveTo','Movieclip','MovieClipLoader','multiline','muted','name','names','NaN',
				'ne','NEGATIVE_INFINITY','NetConnection','NetStream','newline','nextFrame',
				'nextScene','nextSibling','nodeName','nodeType','nodeValue','not','Number','Object',
				'on','onActivity','onChanged','onClipEvent','onClose','onConnect','onData','onDragOut',
				'onDragOver','onEnterFrame','onID3','onKeyDown','onKeyUp','onKillFocus','onLoad','onLoadComplete',
				'onLoadError','onLoadInit','onLoadProgress','onLoadStart','onMouseDown','onMouseMove','onMouseUp',
				'onMouseWheel','onPress','onRelease','onReleaseOutside','onResize','onRollOut','onRollOver',
				'onScroller','onSelect','onSetFocus','onSoundComplete','onStatus','onUnload','onUpdate','onXML',
				'or(logischesOR)','ord','os','parentNode','parseCSS','parseFloat','parseInt','parseXML','password',
				'pause','PGDN','PGUP','PI','pixelAspectRatio','play','playerType','pop','position',
				'POSITIVE_INFINITY','pow','prevFrame','previousSibling','prevScene','print','printAsBitmap',
				'printAsBitmapNum','PrintJob','printNum','private','prototype','public','push','quality',
				'random','rate','registerClass','removeListener','removeMovieClip','removeNode','removeTextField',
				'replaceSel','replaceText','resolutionX','resolutionY','restrict','reverse','RIGHT',
				'rightMargin','round','scaleMode','screenColor','screenDPI','screenResolutionX','screenResolutionY',
				'scroll','seek','selectable','Selection','send','sendAndLoad','separatorBefore','serverString',
				'set','setvariable','setBufferTime','setClipboard','setDate','setFocus','setFullYear','setGain',
				'setHours','setInterval','setMask','setMilliseconds','setMinutes','setMode','setMonth',
				'setMotionLevel','setNewTextFormat','setPan','setProperty','setQuality','setRate','setRGB',
				'setSeconds','setSelectColor','setSelected','setSelection','setSilenceLevel','setStyle',
				'setTextFormat','setTime','setTransform','setUseEchoSuppression','setUTCDate','setUTCFullYear',
				'setUTCHours','setUTCMilliseconds','setUTCMinutes','setUTCMonth','setUTCSeconds','setVolume',
				'setYear','SharedObject','SHIFT','shift','show','showMenu','showSettings',
				'silenceLevel','silenceTimeout','sin','size','slice','smoothing','sort','sortOn','Sound','SPACE',
				'splice','split','sqrt','SQRT1_2','SQRT2','Stage','start','startDrag','static','status','stop',
				'stopAllSounds','stopDrag','String','StyleSheet','styleSheet','substr',
				'substring','super','swapDepths','System','TAB','tabChildren','tabEnabled','tabIndex',
				'tabStops','tan','target','targetPath','tellTarget','text','textColor','TextField','TextFormat',
				'textHeight','TextSnapshot','textWidth','this','throw','time','toggleHighQuality','toLowerCase',
				'toString','toUpperCase','trace','trackAsMenu','try','type','typeof','undefined',
				'underline','unescape','uninstall','unloadClip','unloadMovie','unLoadMovieNum','unshift','unwatch',
				'UP','updateAfterEvent','updateProperties','url','useCodePage','useEchoSuppression','useHandCursor',
				'UTC','valueOf','variable','version','Video','visible','void','watch','width',
				'with','wordwrap','XML','xmlDecl','XMLNode','XMLSocket'
			)
		),'SYMBOLS'=>array('(',')','[',']','{','}','!','@','%','&','|','<','>'), # missing '/' and '*'
	);

	#numbers
	$out = ' '.trim($out).' ';
	$out = preg_replace("@([^#])([0-9]+)@", '\1:w6n:\2:end2:',$out);

	# symbols
	for($i=0; $i<count($as['SYMBOLS']); $i++) {
			$who = $as['SYMBOLS'][$i];
			$out = str_replace($who,':w6s:'.$who.':end2:',$out);
	}
	
	# spacing
	$out = str_replace(" ","&nbsp;",$out);
	
	# single-line comments
	$out = preg_replace_callback("@[^:]{1}//[\S\s]*\r@U", "fixComment", $out);

	# multi-line comments
	$out = preg_replace_callback("@/\*[\S\s]*?\*/@U", "fixComment", $out);

	# keywords
	for($i=0; $i<count($as['KEYWORDS'][3]); $i++) {
			$who = $as['KEYWORDS'][3][$i];
			$out = preg_replace("@([\W])$who([\W])@",'\1:kw3~'.$who.'::end1:\2',$out);
	}
	for($i=0; $i<count($as['KEYWORDS'][2]); $i++) {
			$who = $as['KEYWORDS'][2][$i];
			$out = preg_replace("@([\W])$who([\W])@",'\1:kw2~'.$who.'::end1:\2',$out);
	}
	for($i=0; $i<count($as['KEYWORDS'][1]); $i++) {
			$who = $as['KEYWORDS'][1][$i];
			$out = preg_replace("@([\W])$who([\W])@",'\1:kw1:'.$who.':end2:\2',$out);
	}

	# quotes
	$out = preg_replace("@\'([\S\s]*)?\'@U", ':w6r:\0:end2:', $out);
	$out = preg_replace("@\"([\S\s]*)?\"@U", ':w6r:\0:end2:', $out);

	# make substitutions
	$out = str_replace(':kw1:',"<span class='kw1'>",$out);
	$out = preg_replace("@:kw2~([\w]*)?:@","<a href='wiki.php?id=\$1'>\$1",$out);
	$out = preg_replace("@:kw3~([\w]*)?:@","<a href='wiki.php?id=\$1'>\$1",$out);
	$out = str_replace(':w6c:',"<span class='w6c'>",$out);
	$out = str_replace(':w6r:',"<span class='w6r'>",$out);
	$out = str_replace(':w6n:',"<span class='w6n'>",$out);
	$out = str_replace(':w6s:',"<span class='w6s'>",$out);
	$out = str_replace(':end2:',"</span>",$out);
	$out = str_replace(':end1:',"</a>",$out);

	# newlines and tabs
	$out = str_replace("\t","&nbsp;&nbsp;&nbsp;&nbsp;",$out);
	$out = str_replace("\r","<br />",$out);
	return $out;
}

function fixComment($m) {
  $beg = '';
	if(substr($m[0],0,2) != '/*') {
			$beg = substr($m[0],0,1);
			$m[0] = substr($m[0],1);
	}
	# remove tags from #numbers and #symbols
	$m[0] = str_replace(":w6n:","",$m[0]);
	$m[0] = str_replace(":w6s:","",$m[0]);
	$m[0] = str_replace(":end2:","",$m[0]);
	$swap = ':w6c:';
	# replace each character with its entity equivalent
	for ($i=0; $i < strlen($m[0]); $i++) {
			$swap .= '&#'.ord($m[0][$i]).';';
	}
	# reverse the important tags
	$swap = str_replace("&nbsp;","&nbsp;",$swap);
	$swap = str_replace("&","&",$swap);
	$swap = str_replace("<","<",$swap);
	$swap = str_replace(">",">",$swap);
	$swap .= ':end2:'."\r";
	return $beg.$swap;
}
?>
As you can see, I'm using preg_replace and str_replace way too many times... one time for each keyword, totalling about 600 times. When you run down 1,000 lines of code 600 times... that could take a while.

Can anyone point me in the right direction in terms of shortcuts or better logic? I used a lot of RegEx to save lines of code, so I can explain what the lines are doing if you need me to.

Thanks in advance,
Matt 8)

Posted: Wed Jun 07, 2006 11:11 pm
by feyd
Have you taken a look at Geshi? It has Actionscript highlighting, along with much much more.

http://qbnz.com/highlighter/

Posted: Wed Jun 07, 2006 11:19 pm
by logikal2
yep, i was actually thinking about using GeSHi as part of my wiki. However, I want to do this as sort of a learning experience. Plus, GeSHi is built for multiple languages, and mine is strictly Actionscript (to save code). Everything else on my wiki has been made from scratch. I actually got the KEYWORDS from GeSHi (hell if i'm gonna type those all out myself) :P[/u]

Posted: Fri Jun 09, 2006 7:51 am
by logikal2
anyone?