簡體   English   中英

語法高亮設計

[英]syntax highlighting design

我正在用JavaScript編寫自己的語法熒光筆,這很有趣,並且看到了幾種方法,但是它們都有優點,還有一些我無法解決的嚴重缺點。 你們如何看待這些方法,還有我遺漏的更好的方法嗎?

假設條件

突出顯示的代碼存在於單個字符串中。

方法

  1. 以字符串形式處理代碼,並使用正則表達式查找模式。
    優點
    易於定義和搜索模式
    缺點
    難以忽視引號或注釋中的關鍵字

  2. 用空格和換行符分隔字符串,然后遍歷數組。
    優點
    易於跟蹤范圍
    缺點
    拆分后很難跟蹤空格和換行符


編輯: 詞法分析
因此,如果我理解的話,可以使用詞法分析將字符串分解為標記。 這聽起來有點像方法2? 您如何處理將令牌重新組裝到原始字符串中的方法?

注意:這使用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);

我不會斷言這是最有效的方法,也可以做到最好,但它確實有效。 還有可能在那里我沒有ID'd一些錯誤,但(與1我是知道的,但還沒有得到解決,以固定),但是這應該給你的,你怎么去這個如果你喜歡一個想法。

我建議的實現方法是創建一個textarea或某些內容,並在單擊按鈕或某物時運行插件(就測試而言,這是一個不錯的主意),當然,您可以將文本區域中的文本設置為一些起始代碼以確保它可以正常工作(提示:可以將標簽放在<textarea>標簽之間,它將顯示為文本,而不是HTML)。

另外,blockComment是一個布爾值,請確保傳遞false,因為true會觸發塊引用。 如果您決定逐行解析內容,例如:

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

做類似的事情:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM