论坛首页 Web前端技术论坛

1kjs,再造Js语法高亮,创加亮准确率之最,首创各种便利功能!

浏览 12074 次
精华帖 (7) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-09-03  
javascript中大括号的多义性,注定使用正则进行分析是不现实的
如果追求的是“好用”、“简小”,那么正则无疑是一个好工具,完成80%以上的需求而不会引入太大的复杂度
但如果追求“准确率之最”,恐怕正则是顶不住的

所以我个人不建议楼主以“准确率之最”这样的词进行宣传和推广,一个高亮功能需要的不仅仅是准确率,还有很多其他的路可以走……
0 请登录后投票
   发表时间:2011-09-04  
支持楼主,赞,
0 请登录后投票
   发表时间:2011-09-04   最后修改:2011-09-04
前一阵也写过一个这方面的代码加亮,但只实现了JS部分,没有实现html和CSS部分。
我的代码只是楼主实现的功能的一个子集,但优点是简单,对于不太复杂、比较规矩
的代码,没有问题,加亮mootools.js、JQuery等类库几乎和我的notepad++上的效果是
一样的。楼主的程序的分析功能做的很好,有些很坑爹的句式都能正确处理,我的代码
处理不了。
<!doctype html> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>color keywords </title> 
<style type="text/css"> 
* { 
  font-family: "新宋体";
} 
  
#txtCode{ 
  width : 100%; 
  height: 200px; 
  resize: vertical; 
} 
  
b.Comments{ 
  color:#159AE0;
  font-weight:500;
} 
  
b.String{ 
  color:#27A735; 
  font-weight:500;
} 
  
b.RegExp{ 
  color:#EA842B;
  font-weight:500;  
} 
  
b.Keywords{ 
  color:#FFAA00;
  font-weight:500;  
} 
  
b.Number{ 
  color:#9C3583;
  font-weight:500;  
} 
  
b.Operator{ 
  color:#FFAA00;
  font-weight:500;  
} 
  
b.LineNo{ 
  background-color	: #2e3436; 
  margin-right		: 5px; 
  color				: #8CBBAD;
  font-weight		: 500;  
} 
  
.Output{ 
  border        : 1px solid #396; 
  color         : white; 
  resize        : both; 
  font-size    	: 16px; 
  width			: 100%;  
  word-wrap		: no-wrap;	/*使不自动换行, 调试中*/
  word-break	: keep-all;  
  background-color: #0B161D; 
} 
</style> 
  
<script type="text/javascript"> 
function colorKeywords(){ 
  var source  = $("txtCode").value; 
 	if( source == "" ) return;      
 	var ds = new Date(); 
 	 
 	var keywords  = "Array|arguments|alert|window|document|location|Boolean|Date|Enumerator|Error|Function|Global|Math|Number|Object|RegExp|String|break|delete|function|return|typeof|case|do|if|switch|var|catch|else|in|this|void|continue|false|instanceof|throw|while|debugger|finally|new|true|with|default|for|null|try|abstract|double|goto|native|static|boolean|enum|implements|package|super|byte|export|import|private|synchronized|char|extends|int|protected|print|throws|class|final|interface|public|transient|const|float|long|short|volatile"; 
 	var operators = "\\+\\+|--|===|==|\\+=|-=|\\*=|%=|~=|\\^=|&=|>=|<=|>|<|!=|!|\\|=|\\+|-|\\*|%|=|\\?|\\:|\\{|\\}|\\(|\\)|\\[|\\]|&&|&|\\|\\||\\|"; 
 				   
 	//解析优先级: 注释 > 字符串 > 正则 > 关键字 > 数字 > 运算符  > \s\n\t等占位符 
 	var regStr = (
          "(/\\*[\\S\\s]*?\\*/|//.*?\\r?\\n)" 
 				+ "|((?:\"(?:[^\"]*?\\\\\")*.*?\")|(?:'(?:[^']*?\\\\')*.*?'))" 
 				+ "|(/(?:[^/]+?\\\\/)*.*?/[a-zA-Z]*)" 
 				+ "|(\\b(?:"+keywords+")\\b)" 
 				+ "|(\\b\\d+\\b)" 
 				+ "|("+ operators +")"        //不需要的话可以去掉此行
 				+ "|((?:\\r?\\n)|\\s|\\t)"    //注意\s会匹配换行符\n, 因此换行符的匹配需要提前
      );    
  var parseReg= new RegExp(regStr, "g"); 
 	 
 	//格式化数字函数 
 	var formatNo = function(n){ 
		if( n < 10 ){ 
			return "&nbsp;&nbsp;&nbsp;&nbsp;" + n; 
		}else if(n  < 100 ){ 
			return "&nbsp;&nbsp;&nbsp;" + n; 
		}else if(n  < 1000){ 
			return "&nbsp;&nbsp;" + n; 
		}else if(n  < 10000){ 
			return "&nbsp;" + n; 
		}else{ 
			return n; 
		} 
	}; 
 	 
  //处理字符串中的特殊字符,并在需要换行的时候添加行号 
  var lineNo	  = 1; 
  var handleStr = function(str){
    return str.replace(/<|>|&|\r?\n|\s|\t/g, function(match){ 
      switch( match ){ 
        case "<" 	: return "&lt;"		; 
        case ">" 	: return "&gt;"		; 
        case "&" 	: return "&amp;"	; 
        case " " 	: return "&nbsp;"	; 				
        case "\t"	: return "&nbsp;&nbsp;&nbsp;&nbsp;";
        
        case "\n"	  : 
        case "\r\n" : 
          return "<br/><b class='LineNo'>" + formatNo(++lineNo) + ".</b>";  
      } 
    }); 
  };	 
    
  //对关键字进行着色 
  var output = source.replace(parseReg, function(){ 
    var args    = arguments,
        lstIdx  = args[args.length - 2],
        match   = args[0],
        preChar = lstIdx > 0  
                ? source.charAt(lstIdx-1) 
                : "";
                
    if (args[1])  return "<b class='Comments'>"  + handleStr(match) + "</b>";
    if (args[2])  return "<b class='String'  >"  + handleStr(match) + "</b>";  
    if (args[3])  return "<b class='RegExp'  >"  + handleStr(match) + "</b>"; 
    if (args[4])  return  (preChar != "$")
                         ? "<b class='Keywords'>"+ match + "</b>" 
                         : match;       
    if (args[5])  return  (preChar != "$")
                         ? "<b class='Number'>"	+ match + "</b>" 
                         : match;
    if (args[6])  return "<b class='Operator'>"	+ handleStr(match) + "</b>";
    if (args[7])  return handleStr(match);     

    return match; 
  }); 
  output = "<b class='LineNo'>" + formatNo(1) + ".</b>" + output;		    
   
  //计算耗时 
  var de = new Date();	 
  alert("处理字符串耗时:" + (de - ds)); 
   
  //输出格式化后的内容 
  $("output").innerHTML = output;     
} 
  
//辅助代码---------------------------------------  
function $(id){ 
    return document.getElementById(id); 
} 
  
function clearOutput(){ 
    $("output").innerHTML="";  
} 
</script> 
</head> 
<body> 
  
<input type="button" value="代码着色" onClick="colorKeywords()"    /> 
<input type="button" value="清空输出" onClick="clearOutput()"    /> 
<br/> 
<br/> 
  
请输入要着色的代码: 
<textarea id="txtCode"> 
/**--------------------------- 
* test multiline comments 
* @author jianbo.wang 
*/
  
function(){ 
   //测试单行注释着色 
    
   /**-------------------------- 
   * 测试多行注释着色. 
   *--------------------------*/ 
  
   //测试字符串着色. 
   print("\"hello world!\""); 
   print('will output:"hello world!"'); 
     
   //测试正则着色 
   var reg = /(<\/?\w+.*?>)|(\s)/g; 
     
   //测试关键字着色 
   var output, _window, $window,  
       c= window.alert,     d= $window.alert,    e= _window.alert,  
       f= window._alert,     g= $window._alert,     h= _widnow._alert 
       i= window.$alert,     j= $window.$alert,    k= _window.$alert; 
     
   for(var i=0; i <100; i++){ 
       output = "Welcome user" + i; 
       alert(output);        
   } 
     
   //测试数字着色 
   var $1, $2, _1, _2, a = 100, b= "200", $100, _200, c="$200", d="_100"; 
     
     
   //运算符着色测试 
   var index = 0; 
   var user = { 
       name : "张三", 
       age  : 12, 
       index: index++ 
   }; 
     
   var a = 0; 
   a++; a--; a+="hello"; a+=100; a-=1; a*=1; a%=1; a>=1; a <=1; a > b; a != 2; 
   (a === 1    ) ? true : false;  
   (a ==  1    ) ? true : false; 
   (a =   1    ) ? true : false; 
   (a >   1 ) ? true : false; 
   if( a > 1 || a  < 0 || (a == "string" && b == "number" ) return false; 
}  

//测试输出渲染函数  
function colorKeywords(){ 
    var source  = $("txtCode").value; 
 	if( source == "" ) return;      
 	var ds = new Date(); 
 	 
 	var keywords  = "Array|arguments|alert|window|document|location|Boolean|Date|Enumerator|Error|Function|Global|Math|Number|Object|RegExp|String|break|delete|function|return|typeof|case|do|if|switch|var|catch|else|in|this|void|continue|false|instanceof|throw|while|debugger|finally|new|true|with|default|for|null|try|abstract|double|goto|native|static|boolean|enum|implements|package|super|byte|export|import|private|synchronized|char|extends|int|protected|print|throws|class|final|interface|public|transient|const|float|long|short|volatile"; 
 	var operators = "\\+\\+|--|===|==|\\+=|-=|\\*=|%=|~=|\\^=|&=|>=| <=|>| <|!=|!|\\|=|\\+|-|\\*|%|=|\\?|\\:|\\{|\\}|\\(|\\)|\\[|\\]|&&|&|\\|\\||\\|"; 
 				   
 	//解析优先级: 注释 > 字符串 > 正则 > 关键字 > 数字 > 运算符  > \s\n\t等占位符 
 	var regStr 	= (
         "(/\\*[\\S\\s]*?\\*/|//.*?\\r?\\n)" 
 				+ "|((?:\"(?:[^\"]*?\\\\\")*.*?\")|(?:'(?:[^']*?\\\\')*.*?'))" 
 				+ "|(/(?:[^/]+?\\\\/)*.*?/[a-zA-Z]*)" 
 				+ "|(\\b(?:"+keywords+")\\b)" 
 				+ "|(\\b\\d+\\b)" 
 				+ "|("+ operators +")"        //不需要的话可以去掉此行
 				+ "|((?:\\r?\\n)|\\s|\\t)"    //注意\s会匹配换行符\n, 因此换行符的匹配需要提前
     );   
  var parseReg= new RegExp(regStr, "g"); 
 	 
 	//格式化数字函数 
 	var formatNo = function(n){ 
		if( n  < 10 ){ 
			return "&nbsp;&nbsp;&nbsp;&nbsp;" + n; 
		}else if( n  < 100 ){ 
			return "&nbsp;&nbsp;&nbsp;" + n; 
		}else if( n  < 1000){ 
			return "&nbsp;&nbsp;" + n; 
		}else if( n  < 10000){ 
			return "&nbsp;" + n; 
		}else{ 
			return n; 
		} 
	}; 
 	 
 	//处理字符串中的特殊字符,并在需要换行的时候添加行号 
 	var lineNo		= 1; 
 	var handleStr 	= function(source){	 
		return source.replace(/<|>|&|\s|\t|\r?\n/g, function(match){ 
			switch( match ){ 
				case "<" 	: return "&amp;lt;"		; 
				case ">" 	: return "&amp;gt;"		; 
				case "&" 	: return "&amp;amp;"	; 
				case " " 	: return "&amp;nbsp;"	; 
				case "\t"	: return "&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"; 
				case "\n"	: 
				case "\r\n" : 
					return "<br/><b class='LineNo'>" + formatNo(++lineNo) + ".</b>"; 
			} 
		}); 
	};	 
      
    //对关键字进行着色 
    var output = source.replace(parseReg, function(){ 
		var args    = arguments; 
		var lstIdx  = args[args.length - 2]; 
		var match   = args[0]; 
		var preChar = lstIdx > 0  
					? source.charAt(lstIdx-1) 
					: "";					 
		 
		if( args[1] ) return "<b class='Comments'>"  + handleStr(match) + "</b>";                
		if( args[2] ) return "<b class='String'  >"  + handleStr(match) + "</b>";                     
		if( args[3] ) return "<b class='RegExp'  >"  + handleStr(match) + "</b>";                     
		if( args[4] ) return  (preChar != "$") 
							 ? "<b class='Keywords'>"+ match + "</b>" 
							 : match;                     
		if( args[5] ) return  (preChar != "$") 
							 ? "<b class='Number'>"	+ match + "</b>" 
							 : match;                     
		if( args[6] ) return "<b class='Operator'>"	+ handleStr(match) + "</b>";	 
		if( args[7] ) return handleStr(match);                     
		return match; 
    }); 
 	output = "<b class='LineNo'>" + formatNo(1) + ".</b>" + output;		    
 	 
 	//计算耗时 
 	var de = new Date();	 
 	alert("处理字符串耗时:" + (de - ds)); 
 	 
 	//输出格式化后的内容 
     $("output").innerHTML = output;     
} 
  
function $(id){ 
    return document.getElementById(id); 
} 
  
function clearOutput(){ 
    $("output").innerHTML="";  
} 
</textarea> 
<br/> 
<br/> 
  
代码着色结果:
<div id="output" class="Output"	> 
  codes output here! 
</div> 
  
</body> 
</html>
0 请登录后投票
   发表时间:2011-09-05  
确实非常不错的一个JS库,学习了,谢谢分享。
0 请登录后投票
   发表时间:2011-09-05  
楼主可以参考的看一下ace项目。google group上貌似就有Ace的项目。已经实现了js高亮显示。感觉那个很棒~
0 请登录后投票
   发表时间:2011-09-05  
int08h 写道
javascript中大括号的多义性,注定使用正则进行分析是不现实的
如果追求的是“好用”、“简小”,那么正则无疑是一个好工具,完成80%以上的需求而不会引入太大的复杂度
但如果追求“准确率之最”,恐怕正则是顶不住的

所以我个人不建议楼主以“准确率之最”这样的词进行宣传和推广,一个高亮功能需要的不仅仅是准确率,还有很多其他的路可以走……


谢谢建议,其实看网上很多有名的加亮对正则处理的不好,所以就处理了下正则,有点纠结了,某些正则确实无需那么准确,现在是以牺牲一定性能来达到准确性的,不过这里的执行功能不知道大家看见没有,不知道这个功能需求怎么样!

就像51js那样,一段html或者js可以被执行!
0 请登录后投票
   发表时间:2011-09-05   最后修改:2011-09-05
xingqiliudehuanghun 写道
前一阵也写过一个这方面的代码加亮,但只实现了JS部分,没有实现html和CSS部分。
我的代码只是楼主实现的功能的一个子集,但优点是简单,对于不太复杂、比较规矩
的代码,没有问题,加亮mootools.js、JQuery等类库几乎和我的notepad++上的效果是
一样的。楼主的程序的分析功能做的很好,有些很坑爹的句式都能正确处理,我的代码
处理不了。


不错,其实我有个更加简单的版本,代码很短,不到100行,和你的代码风格是蛮像的,一片片case,不过我的准确性也是相当不错的 ,基本上的正则问题也都做了解决!

地址:http://www.tree88.com/?post=16

 

0 请登录后投票
   发表时间:2011-09-05  
31212 写道
楼主可以参考的看一下ace项目。google group上貌似就有Ace的项目。已经实现了js高亮显示。感觉那个很棒~

 

能给个地址吗?居然没搜索到!学习学习,呵呵!

0 请登录后投票
   发表时间:2011-09-06  
JS中的正则真是个麻烦的问题, 如果想做的精度比较高的话,估计用正则就不行了,可能需要想解析器一样,逐个字符进行分析。
0 请登录后投票
   发表时间:2011-09-06  
黑底的配色 比较帅
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics