2010-11-22 108 views
0

我正在編寫我自己的語法高亮在JavaScript的樂趣,並看到一些方法,但他們都有優點和一些非常嚴重的缺點,我不能解決。你們對這些方法有什麼看法,有沒有更好的方法,我錯過了?語法高亮設計

假設

代碼突出存在於單個字符串。

途徑

  1. 款待代碼在它的字符串形式和使用正則表達式來進行匹配。
    優點
    簡單定義和搜索模式
    缺點
    很難忽略的關鍵字引號內或由空格和換行,並遍歷所有的評論

  2. 分割字符串陣列。
    優點
    易於保持的範圍
    缺點軌道
    很難跟蹤的空格和換行拆分後


編輯:詞法分析
所以,如果我理解它,使用詞法分析將字符串分解爲令牌。這聽起來很像2號方法嗎?你如何將標記重新組裝成原始字符串?

+7

3.真正分析源代碼爲標記,正確地對待他們。優點:正確。缺點:很難。 – 2010-11-22 22:37:22

+1

你的#2,如果你確實是指字面意思*「...由空格和換行符......」*將基本上任何與B派生語法(C,C++,C#,Java,JavaScript,D,和其他十幾個人)。考慮if(x> y){foo();} else {bar();}`。 – 2010-11-22 22:38:42

回答

1

注:這使用jQuery。如果你願意的話,它可以重寫爲直接使用javascript。

其實我寫了一個有趣的小插件,這是否:

(function($) { 
$.fn.codeBlock = function(blockComment) { 

    // Setup keyword regex 
    var keywords = /(abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|default|delete|do|double|else|enum|export|extends|final|finally|float|for|function|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|super|switch|synchronized|this|throw|throws|transient|try|typeof|var|void|volatile|while|with|true|false|prototype)(?!\w|=)/gi; 

    // Booleans to toggle comment, regex, quote exclusions 
    var comment = false; 
    var quote = false; 
    var regex = false; 

    /* Array used to store values of regular expressions, quotes, etc. 
    so they can be used to ID locations to be skipped durring keyword 
    regexing. 
    */ 
    var locator = new Array(); 
    var locatorIndex = 0; 

    if (blockComment) locator[locatorIndex++] = 0; 

    var text = $(this).html(); 
    var continuation; 
    var numerals = /[0-9]/; 

    var arr = ($(this).html()).split(""); 
    var outhtml = ""; 

    for (key in arr) { 
    // Assign three variables common 'lookup' values for faster aquisition 
    var keyd = key; 
    var val = arr[keyd]; 
    var nVal = arr[keyd - 1]; 
    var pVal = arr[++keyd]; 

    if ((val == "\"" || val == "'") && nVal != "\\") { 
    if (quote == false) { 
    quote = true; 
    outhtml += val; 
    } 
    else { 
    outhtml += val; 
    quote = false; 
    } 
    locator[locatorIndex++] = parseInt(key); 
    } 
    else if (numerals.test(val) && quote == false && blockComment == false && regex == false) { 
    outhtml += '<span class="num">' + val + '</span>'; 
    } 
    else if (val == "/" && nVal != "<") { 
    var keys = key; 
    if (pVal == "/") { 
    comment = true; 
    continuation = key; 
    break; 
    } 
    else if (pVal == "*") { 
    outhtml += "/"; 
    blockComment = true; 
    locator[locatorIndex++] = parseInt(key); 
    } 
    else if (nVal == "*") { 
    outhtml += "/"; 
    blockComment = false; 
    locator[locatorIndex++] = parseInt(key); 
    } 
    else if (pVal == "[" && regex == false) { 
    outhtml += "<span class='res'>/"; 
    regex = true; 
    } 
    else { 
    outhtml += "/"; 
    } 
    } 
    else if (val == "," || val == ";" && regex == true) { 
    outhtml += "</span>" + val; 
    regex = false; 
    } 
    else { 
    outhtml += val; 
    } 
    } 

    if (comment == true) { 
    outhtml = outhtml.replace(keywords, "<span class='res'>$1</span>"); 
    outhtml += '<span class="com">'; 
    outhtml += text.substring(continuation, text.length); 
    outhtml += '</span>'; 
    } 
    else { 
    if ((locator.length % 2) != 0) locator[locator.length] = (text.length - 1); 

    if (locator.length != 0) { 
    text = outhtml; 

    outhtml = text.substring(0, locator[0]).replace(keywords, "<span class=\"res\">$1</span>"); 

    for (var i = 0; i < locator.length;) { 
    qTest = text.substring(locator[i], locator[i] + 1); 
    if (qTest == "'" || qTest == "\"") outhtml += "<span class=\"quo\">"; 
    else outhtml += "<span class=\"com\">"; 

    outhtml += text.substring(locator[i], locator[++i] + 1) + "</span>"; 

    outhtml += text.substring(locator[i] + 1, locator[++i]).replace(keywords, "<span class=\"res\">$1</span>"); 
    } 
    } 
    else { 
    outhtml = outhtml.replace(keywords, "<span class=\"res\">$1</span>"); 
    } 
    } 

    text = outhtml; 
    $(this).html(text); 
    return blockComment; 
} 
})(jQuery); 

我不會要求它這樣做還是最好的最有效的方式,但它確實工作。在那裏我可能還有一些bug,我還沒有ID'd(還有1我知道,但沒有得到解決)但這應該讓你知道如何你可以去這個,如果你喜歡。

我建議的實現是創建一個textarea或者什麼,並且當你點擊一個按鈕或者某個東西時(只要測試它就是一個好主意)就可以運行插件,當然你也可以設置文本textarea的一些起始代碼,以確保它的工作(提示:你可以把標籤放在<textarea>標籤之間,它會呈現爲文本,而不是HTML)。

此外,blockComment是一個布爾值,確保傳遞false,因爲true會觸發塊引用。如果您決定通過線來分析的東西線,如:

<a>code</a> 
<a>some more code</a> 

做這樣的事情:

blockComment = false; 
$("a").each(function() { 
    blockComment = $(this).codeBlock(blockComment); 
});