/*--
标题:代码高亮控件
设计:王集鹄
博客:http://blog.csdn.net/zswang
日期:2009年5月15日
--*/var Highlight = {
analyze: function(code, lang) {
if (!lang) return null;
var result = [];
var find = true;
var last = "";
while (find && code) {
find = false;
var j;
for (var i = 0; i < lang.syntaxs.length; i++) {
if (lang.syntaxs[i].start) {
var exists = false;
for (j = 0; j < lang.syntaxs[i].start.length; j++) {
if (last == lang.syntaxs[i].start[j]) {
exists = true;
break;
}
}
if (!exists) continue;
}
var match = lang.syntaxs[i].pattren.exec(code);
if (match) {
var methods = lang.syntaxs[i].methods;
if (methods) {
for (j = 0; j < methods.length; j++) {
var method = methods[j];
if (!method) continue;
if (!match[j + 1]) continue;
if (this[method] && this[method].syntaxs) {
var items = this.analyze(match[j + 1], this[method]);
for (var k = 0; k < items.length; k++) {
result.push(items[k]);
}
} else result.push({ name: method, text: match[j + 1] });
}
} else {
if (lang.syntaxs[i].name) {
var item = { name: lang.syntaxs[i].name, text: match[0] };
if (item.name == "Identifier" && lang.identifiers) {
for (j = 0; j < lang.identifiers.length; j++)
if (lang.identifiers[j].pattren.test(item.text))
item.name = lang.identifiers[j].name;
}
if (!/^(Whitespace|LineComment|MultiComment)$/i.test(item.name)
&& !/\)$/.test(item.text)) last = item.name;
result.push(item);
}
}
code = code.substr(match[0].length);
find = true;
break;
}
}
}
if (!find && code) result.push({ name: "Unknown", text: code });
return result;
}
, exportHtml: function(code, lang) {
var items = this.analyze(code, lang);
var html = [];
html.push("<pre class=\"Code\"><code>");
for (var i = 0; i < items.length; i++)
html.push("<span class=\"" + items[i].name + "\">"
+ items[i].text.replace(/</g, "&lt;").replace(/>/g, "&gt;") 
+ "</span>");
html.push("</pre></code>");
return html.join("");
}
, attribute: {
syntaxs: [    
{ pattren: /^\s+/, name: "Whitespace" }
, { pattren: /^(=|:|;|\/)/, name: "Symbol" }
, { pattren: /^('[^']*'|"[^"]*")/, name: "String" }
, { pattren: /^[\w\/\-_]+/, name: "Variant" }
]
}
, property: {
syntaxs: [    
{ pattren: /^\s+/, name: "Whitespace" }
, { pattren: /^\/\*[\s\S]*?\*\//, name: "MultiComment" }
, { pattren: /^([a-zA-Z0-9_\-]+)(\s*)(:)(\s*)([^;]*)(;|$)/, methods: ["Variant", "Whitespace", "Symbol", "Whitespace", "String", "Symbol"] }
]
}
, css: {
syntaxs: [    
{ pattren: /^\s+/, name: "Whitespace" }
, { pattren: /^\/\*[\s\S]*?\*\//, name: "MultiComment" }
, { pattren: /^(((\.|#)[a-zA-Z0-9_\-]+[\s,]*)+)(\{)([\s\S]*?)(\})/,  methods: ["Function", null, null, "Symbol", "property", "Symbol"] }

]
}
, javascript: {
syntaxs: [
{ pattren: /^\s+/, name: "Whitespace" }
, { pattren: /^\/\/.*/, name: "LineComment" }
, { pattren: /^\/\*[\s\S]*?\*\//, name: "MultiComment" }
, { pattren: /^\/([^\\\/\n\r]*(\\.)*)*\/(i|m|g)*/, name: "Regex", start: ["", "Symbol"] }
, { pattren: /^(~|\+|\-|\*|\(|\)|\[|\]|\{|\}|\||\;|:|=|<|>|\.|\,|\%|\!|&|\?|\^)+/, name: "Symbol" }
, { pattren: /^\//, name: "Symbol" }
, { pattren: /^(\d+(?!\.|x|e|d|m)u?)|^0x([\da-fA-F]+(?!\.|x|m)u?)|^NaN/, name: "Number" }
, { pattren: /^(\d+)?\.\d+((\+|\-)?e\d+)?(m|d|f)?|^\d+((\+|\-)?e(\+|\-)?\d+)?(m|d|f)?/, name: "Float" }
, { pattren: /^"([^\\"]*(\\.)*)*"/, name: "String" }   
, { pattren: /^'([^\\']*(\\.)*)*'/, name: "String" }
, { pattren: /^[\w$_]+/, name: "Identifier" }
]
, identifiers: [
{ pattren: /^(break|delete|function|return|typeof|case|do|if|switch|var|catch|else|in|this|void|continue|false|instanceof|throw|while|debugger)$/, name: "Reserved" }
, { pattren: /^(finally|new|true|with|default|for|null|try|abstract|double|goto|native|static|boolean|enum|implements|package|super|byte|prototype)$/, name: "Reserved" }
, { pattren: /^(export|import|private|synchronized|char|extends|int|protected|throws|class|final|interface|public|transient|const|float|long|short|volatile)$/, name: "Reserved" }
, { pattren: /^(Array|String|Boolean|undefined|Object|Enumerator|Error|Math)$/, name: "Type" }
]
}
, xhtml: {
syntaxs: [    
{ pattren: /^\s+/, name: "Whitespace" }
, { pattren: /^<!--[\s\S]*?-->/, name: "MultiComment" }
, { pattren: /^(<!)([\s\S]*?)(>)/, methods: ["Symbol", "attribute", "Symbol"] }
, { pattren: /^(<\?)(xml\b)([\s\S]*?)(\?>)/, methods: ["Symbol", "Reserved", "attribute", "Symbol"] }
, { pattren: /^(<\?)(php\b)(.*?)(\?>)/, methods: ["Symbol", "Reserved", "php", "Symbol"] }
, { pattren: /^(<\?)(php\b)([\s\S]*?)(\n\?>|$)/, methods: ["Symbol", "Reserved", "php", "Symbol"] }
, { pattren: /^(<%@)([\s\S]*?)(%>)/, methods: ["Symbol", "attribute", "Symbol"] }
, { pattren: /^(<%)([\s\S]*?)(%>)/, methods: ["Symbol", "Text", "Symbol"] }
, { pattren: /^(<)(style\b)(([^>"']*(".*?"|'.*?')*)*?)(>)([\s\S]*?)(<\/)(style)(>)/i, methods: ["Symbol", "Type", "attribute", null, null, "Symbol", "css", "Symbol", "Type", "Symbol"] }
, { pattren: /^(<)(script\b)(([^>"']*(".*?"|'.*?')*)*?)(>)([\s\S]*?)(<\/)(script)(>)/i, methods: ["Symbol", "Type", "attribute", null, null, "Symbol", "javascript", "Symbol", "Type", "Symbol"] }
, { pattren: /^(<\/?)([\w\-]+)(([^>"']*(".*?"|'.*?')*)*?)(>)/i, methods: ["Symbol", "Type", "attribute", null, null, "Symbol"] }
, { pattren: /^[^<]+/i, name: "Text" }
]  
}
, php: {
syntaxs: [
{ pattren: /^\s+/, name: "Whitespace" }
, { pattren: /^(\/\/|#).*/, name: "LineComment" }
, { pattren: /^\/\*[\s\S]*?\*\//, name: "MultiComment" }
, { pattren: /^(~|\+|\-|\*|\(|\)|\[|\]|\{|\}|\||\;|:|=|<|>|\.|\,|\%|\!|&|\?|\^|@)+/, name: "Symbol" }
, { pattren: /^\//, name: "Symbol" }
, { pattren: /^(\d+(?!\.|x|e|d|m)u?)|^0x([\da-fA-F]+(?!\.|x|m)u?)|^NaN/, name: "Number" }
, { pattren: /^(\d+)?\.\d+((\+|\-)?e\d+)?(m|d|f)?|^\d+((\+|\-)?e(\+|\-)?\d+)?(m|d|f)?/, name: "Float" }
, { pattren: /^"([^\\"]*(\\.)*)*"/, name: "String" }   
, { pattren: /^'([^\\']*(\\.)*)*'/, name: "String" }
, { pattren: /^\$[\w_]*/, name: "Variant" }
, { pattren: /^[\w_]+/, name: "Identifier" }
]
, identifiers: [
{ pattren: /^(require_once|include|and|or|xor|__FILE__|exception|php_user_filter|__LINE__|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|each|echo|else|elseif|empty)$/, name: "Reserved" }
, { pattren: /^(enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|for|foreach|function|global|if|isset|list|new|old_function|print|return|static|switch|unset|use|var|while|__FUNCTION__|__CLASS__|__METHOD__)$/, name: "Reserved" }
, { pattren: /^(NULL|FALSE|TRUE)$/, name: "Variant" }
]
}
};完整演示代码:http://www.renrousousuo.com/scripts/Highlight.html包括了:html(xml)、javascript、php、css、csharp、delphi如发现问题和改进意见请通知我一声。

解决方案 »

  1.   

    补充调用Demo:
    <html>
    <head>
    <title>代码高亮测试</title>
    <style type="text/css">
    .Code{font-family:Courier New;font-size:14px;background-color:#EEEEEE;}
    .Code .Whitespace{}
    .Code .Regex{color:Lime;}
    .Code .LineComment, .MultiComment{font-weight:bold;font-style:italic;color:Gray;}
    .Code .CompilerDirective{color:Green;}
    .Code .Symbol{color:Blue;}
    .Code .Number, .Float{color:Red;font-weight:bold;}
    .Code .String, .Character{color:Maroon;}
    .Code .Identifier{}
    .Code .Reserved{font-weight:bold;}
    .Code .Type{color:#2B91AF;}
    .Code .Variant{color:Red;}
    .Code .Function{color:Fuchsia;}
    .Code .Unknown{font-style:italic;background-color:Black;color:White;}
    </style>
    </head>
    <body>
    <script language="ecmascript"type="text/javascript" src="Highlight.js"></script>
    <textarea id="textareaCode" rows="10" cols="*" style="width:100%"></textarea>
    <div>
    <select id="selectLang">
    <option value="attribute">attribute</option>
    <option value="css">css</option>
    <option value="javascript">javascript</option>
    <option value="csharp">csharp</option>
    <option value="delphi">delphi</option>
    <option value="mssql">mssql</option>
    <option value="xhtml">xhtml</option>
    </select>
    <input type="button" onclick="buttonStart_Click()" value="处理" />
    </div>
    <div id="div_html"></div>
    <script type="text/javascript">
    function $(id) { return document.getElementById(id); }
    function buttonStart_Click() {
    $("div_html").innerHTML = Highlight.exportHtml(
    $("textareaCode").value
    , Highlight[$("selectLang").value]
    );
    }
    </script>
    </body>
    </html>
      

  2.   

    IE 6.0.3790 直接打开演示页后, select 中内容不正常,刷新一下就可以了,是我浏览器问题?
    可惜不能上传图片,说不太清楚
      

  3.   

    可能是本机IE的问题,换台机器没这个现象,不过原代码上加入
    <meta http-equiv="Content-Type" content="text/html; charset=gbk" />
    在本机测试也没那个问题。
    说不清楚
      

  4.   

    lz做得不错,另外建议参考一下CodePress
      

  5.   


    有几个正则表达式不是那么好写比较典型的是:匹配“正则表达式”
    /^\/([^\\\/\n\r]*(\\.)*)*\/(i|m|g)*/匹配“HTML标签”
    /^(<\/?)([\w\-]+)(([^>"']*(".*?"|'.*?')*)*?)(>)/i可能会出现,标签属性中嵌套标签的情况:
    <a onclick="document.write('<a href=#>测试</a>')"></a>这里采用了贪婪匹配的方法
    (
      [^>"']*  -- 先匹配不冲突的字符
      (".*?"|'.*?')* [color=#FF0000]-- 然后将冲突的字符成对匹配掉
    )* [/color]-- 重复上述情况
      

  6.   

    代码就是最好的文档。
    核心代码不多,可逐行看。
    原理就是按优先级扫描字符串属于什么语法元素。
    对于html就比较复杂一些,需要嵌套分析(一个语言里嵌套另一种语言),这里用正则的分组嵌套分析。
      

  7.   

    在判断是否为正则表达式的时候需要特殊处理。
    如下情况:
    var i = 1 / 2 + 2 / 3;两个除号可能被匹配为正则,,,所以要判断上一个元素是不是标点符号。后来又碰到如下情况:
    var i = (1 + 2) / 2 + 2 / 3;前面是标点符号,但也不是正则。
      

  8.   

    study
    .
    人力资源
      

  9.   

    怎么只有前面部分文字有变化,并且如果先Attribute、css、Javascript变化后,再回头选开始选Javascript、css、Attribute,效果都不一样。
      

  10.   

    没有学JavaScript,应该也是挺难的吧!
      

  11.   

    收藏下  www.tg68.cn我搞的网站  希望大家给点建议