代码改变世界

用Javascript replace方法完成代码高亮插件——支持JS\CSS\HTML(支持html里面的JS,CSS)

2012-11-22 20:30  VVG  阅读(2710)  评论(3编辑  收藏

看到语法高亮的帖子,然后下班路上想了一下,有一个具体的思路,但是不知道别人如何实现,总觉得自己想法会太复杂,

主要就是用到Javascript的字符串的处理方法replace,然后利用正则表达式替换包裹HTML标签,全程都是字符串的处理,

输出的也是字符串。先把自己实现的发上来,只是简单的字符串替换,复杂的情况还满足不了,特别是特殊的注释与正则表达式不能够很好的识别

点击下载此代码

演示如下:

语法高亮

在这里输入代码:





 

代码高亮用到的CSS:

/* 代码高亮CSS start */
        .codePre{width: 900px; margin-top: 5px;}
        .codePre { background: #282525; color: #fff; font: 14px/1.5em "Consolas",
        "Bitstream Vera Sans Mono", "Courier New", 'microsoft Yaheis'; border-radius: 8px; padding: 10px; }
        .codePre ol li { word-break: break-all; }
        .codePre ol li:nth-child(odd){background-color:#282828;}
        .codePre span.keyWords { color: #99ffdd; font-weight: bold; }
        .codePre span.string { color: #75c894; font-weight: bold; }
        .codePre span.string span { color: #75c894 !important; font-weight: bold; }
        .codePre span.string span.string { color: #3adf3a !important; font-weight: bold; }
        .codePre span.lineComment { color: #808080; }
        .codePre span.lineComment span { color: #808080 !important; }
        .codePre span.blockComment { color: #808080; font-style: italic; }
        .codePre span.blockComment span { color: #808080 !important; }
        .codePre span.blockComment span.attribute { color: #808080 !important; }
        .codePre span.blockComment span.string { color: #808080 !important; }
        .codePre span.nummber { color: red; }
        .codePre span.reg { background: #ccc; }
        .codePre span.attribute { color: #75c894; font-weight: normal; font-style: italic; }
        .codePre span.attribute span.string { color: #3adf3a; font-weight: bold; }
        .codePre span.class { color: #99cc00; }
        .codePre span.styleName { color: #ccffff }
        .codePre span.styleValue { color:#5bc5c9}
        /* 代码高亮CSS end */

代码高亮JS:

var heighLight = function () {
    /* 高亮正则*/
    var heighLightWords = {
        'javascript':{
            keywords    :/\b(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)\b/g,
            lineComment :/([^\\:])(\/\/.*$)/g,
            blockComment:/\/\*.*?\*\//g,
            string      :/('[^']*?')/g,
            string2     :/("[^"]*?")/g,
            nummber     :/\b([0-9]+)\b/g
        },
        'html'      :{
            string      :/(".*?")/g,
            attribute   :/(<[a-z]+ )(.+?)(\/?>)/ig,
            blockComment:/(<!--.*?-->)/g,
            js          :/(<script(?: .*?)?>)(.+?)(<\/script>)/ig,
            css         :/(<style .*?>)(.+?)(<\/style>)/ig
        },
        'css'       :{
            cssCut      :/((?:[-a-z.:\(\)_#]| )+?)({)(.*?)(})/ig,
            blockComment:/\/\*.*?\*\//g,
        }
    };

    //  转义字符串
    var htmlEncode = function (html) {
        return  html.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n|\r/g, '<br/>')
            .replace(/\s/g, '&nbsp;').replace(/"/g, '&quot;').replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
    };

    //  处理多行注释
    var filterBlockComment = function (str, type) {
        return str.replace(heighLightWords[type].blockComment, function (a) {
            var str = '<span class="blockComment">';
            if (a.indexOf('<br/>') > -1) {
                var arr = a.split('<br/>');
                str += arr.join('</span><br/><span class="blockComment">');
            } else {
                str += a;
            }
            str += '</span>';
            return str;
        })
    };

    //处理HTML里面的JS
    var filterHtmlJs = function (str) {
        return str.replace(heighLightWords.html.js, function (a, b, c, d) {
            //var myStr = b + javascriptReplace(c) + d;
            // return myStr;
            var arr = [];
            c = filterBlockComment(c, 'javascript');
            // 拆分成单行处理
            arr = c.split('<br/>');
            for (var i = 0, n = arr.length; i < n; i++) {
                arr[i] = javascriptReplace(arr[i]);
            }
            c = arr.join('<br/>');
            return b + c + d;
        })
    };

    // 处理HTML里面的CSS
    var filterHtmlCss = function (str) {
        return str.replace(heighLightWords.html.css, function (a, b, c, d) {
            var arr = [];
            c = filterBlockComment(c, 'css');
            c = filterCss(c);
            return b + c + d;
        })
    }

    // 处理纯CSS
    var filterCss = function (str) {
        return str.replace(heighLightWords.css.cssCut, function (a, b, c, d, e) {
            var arr, arr2;
            if (b.indexOf('<br/>') > -1) {
                b.replace(/<br\/>/g, '');
            }
            b = '<span class="class">' + b + '</span>';
            // 替换掉特殊字符,避免里面的分号影响分组
            d = d.replace(/&nbsp;/g, '$');
            d = d.replace(/&quot;/g, '@');
            arr = d.split(';');
            for (var i = 0; i < arr.length; i++) {
                if (!/^(<br\/>|\$)*$/.test(arr[i])) {
                    arr2 = arr[i].split(':');
                    // 如果含有<br/>,不能用span包裹,因为后面以BR来添加OL LI
                    if (arr2[0].indexOf('<br/>') > -1) {
                        // 查找<br/>最后出现的位置
                        var index = arr2[0].lastIndexOf('<br/>');
                        // 加上<br/> 自己的长度
                        index = index + 5;
                        var len = arr2[0].length;
                        arr2[0] = arr2[0].slice(0, index) + '<span class="styleName">' + arr2[0].slice(index, len) + '</span>';
                    } else {
                        arr2[0] = '<span class="styleName">' + arr2[0] + '</span>';
                    }
                    arr2[1] = '<span class="styleValue">' + arr2[1] + '</span>';
                    arr[i] = arr2.join(':');
                }
            }
            d = arr.join(';');
            d = d.replace(/@/g, '&quot;');
            d = d.replace(/\$/g, '&nbsp;');
            return b + c + d + e;
        })
    }

    // replace替换操作
    var javascriptReplace = function (str) {
        // 关键字高亮
        str = str.replace(heighLightWords.javascript.keywords, '<span class="keyWords">$1</span>');
        // 单行注释
        str = str.replace(heighLightWords.javascript.lineComment, '$1<span class="lineComment">$2</span>');
        // 单引号字符串
        str = str.replace(heighLightWords.javascript.string, '<span class="string">$1</span>');
        // 双引号字符串
        str = str.replace(heighLightWords.javascript.string2, '<span class="string">$1</span>');
        // 数字
        str = str.replace(heighLightWords.javascript.nummber, '<span class="nummber">$1</span>');

        return str;
    }

    // jsArrayReplace JS文件分成行处理,返回字符串
    var jsArrayReplace = function (str) {
        var arr = [];
        str = filterBlockComment(str, 'javascript');
        // 拆分成单行处理
        arr = str.split('<br/>');
        for (var i = 0, n = arr.length; i < n; i++) {
            arr[i] = javascriptReplace(arr[i]);
        }
        str = arr.join('<br/>');
        return str;
    }

    var htmlReplace = function (str) {
        // 标签属性 《img .... /》
        str = str.replace(heighLightWords.html.attribute, '$1<span class="attribute">$2</span>$3');
        // 双引号里面
        str = str.replace(heighLightWords.html.string, '<span class="string">$1</span>');

        return str;
    }

    var cssReplace = function (str) {
        str = str.replace();

    }

    // 处理html js 成最后输出的<ol><li></li></ol>格式
    var addOlli = function (str) {
        var arr = [];
        str = str + '<br/>';
        var str2 = '<ol><li>';
        arr = str.split('<br/>');
        // 去除空行
        for(var i=0;i<arr.length;i++){
            if(/^\s*$/.test(arr[i])){
                arr.splice(i,1);
                i--;
            }
        }
        str2 += arr.join('</li><li>');
        str2 += '</li></ol>';
        return str2;
    }

    /* 高亮实现方法 */
    var heighLightO = {
        lightJs  :function (str) {
            // 先转义
            str = htmlEncode(str);
            // 在处理替换关键字等项
            str = jsArrayReplace(str);
            // 隔行处理
            str = addOlli(str);
            return str;
        },
        lightHtml:function (str) {
            // HTML转义
            str = htmlEncode(str);
            // 先处理html多行注释
            str = filterBlockComment(str, 'html');
            // 再处理HTML页内的JS
            str = filterHtmlJs(str);
            // todo 处理HTML页内的css
            str = filterHtmlCss(str);
            // 在处理HTML标签的着色
            str = htmlReplace(str);
            // 隔行处理
            str = addOlli(str);
            return str;
        },
        lightCss :function (str) {
            str = htmlEncode(str);
            str = filterBlockComment(str, 'css');
            str = filterCss(str);
            str = addOlli(str);

            return str;
        }
    };
    return heighLightO;
}();

document.getElementById('go').onclick = function () {
    var type = document.getElementById('choose').value;
    document.getElementById('heighLightCode').innerHTML = heighLight['light' + type](document.getElementById('code').value);
};