2011-10-21 126 views
2

我決定我必須寫我自己的語法熒光筆。到目前爲止它正在工作,但它是實時的(你鍵入,它突出顯示)並且很慢。優化我的語法熒光筆

我會試着解釋它是如何工作的。每次用戶在EditText中鍵入內容時,它都會運行突出顯示器(通過TextWatcher)。熒光筆搜索文本直到找到單詞的開頭,然後搜索,直到找到同一單詞的結尾。一旦它找到一個單詞,它將通過一組關鍵字進行搜索,如果它找到了一個匹配項,它會在該位置設置一個可跨越的字符串。它保持循環直到到達文檔的末尾。

同樣,它的工作到目前爲止(只是在繼續使用這種方法之前嘗試這個想法),但它太慢了。有些時候,只需要經過幾行就可以花費一秒多的時間。它減慢了文本在EditText中出現的速度。 - 在用戶輸入的最後一個位置輸入文本後,我還設置了突出顯示器的起始位置,因此每次都不需要瀏覽整個文檔,它有一點幫助,但不是很大。

這裏是我的EditText的基本:

public class CodeView extends EditText { 
    private int mTxtChangeStart; 
    String mStructures[] = this.getResources().getStringArray(R.array.structures); 

    public CodeView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     addTextChangedListener(inputTextWatcher); 

       ... 
     } 

    TextWatcher inputTextWatcher = new TextWatcher() { 

     @Override 
     public void afterTextChanged(Editable s) { 
      syntaxHighlight(); 
     } 

     @Override 
     public void beforeTextChanged(CharSequence s, int start, int count, 
       int after) { 
      //Set where we should start highlighting 
      mTxtChangeStart = start; 
     } 

     @Override 
     public void onTextChanged(CharSequence s, int start, int before, 
       int count) { 


     } 

    }; 

    private void syntaxHighlight() { 

     //Time how long it takes for debugging 
     long syntime = System.currentTimeMillis(); 
     Log.d("", "Start Syntax Highlight"); 


     //Get the position where to start searching for words 
     int strt = mTxtChangeStart; 

     //Get the editable text 
     Editable txt = getText(); 


     //Back up the starting position to the nearest space 
     try { 
      for(;;) { 
       if(strt <= 0) break; 
       char c = txt.charAt(strt); 

       if(c != ' ' && c != '\t' && c != '\n' && c != '\r') { 
        strt--; 
       } else { 
        break; 
       } 
      } 
     } catch (IndexOutOfBoundsException e) { 
      Log.e("", "Find start position failed: " + e.getMessage()); 
     } 

     //Just seeing how long this part took 
     long findStartPosTime = System.currentTimeMillis(); 
     Log.d("", "Find starting position took " + String.valueOf(System.currentTimeMillis() - findStartPosTime) + " milliseconds"); 

     //the 'end of a word' position 
     int fin = strt; 

     //Get the total length of the search text 
     int totalLength = txt.length(); 

     //Start finding words 
     //This loop is to find the first character of a word 
     //It loops until the current character isnt a space, tab, linebreak etc. 
     while(fin < totalLength && strt < totalLength) { 
      for(;;) { 
       //Not sure why I added these two lines - not needed here 
       //fin++; 
       //if(fin >= totalLength) { break; } //We're at the end of the document 

       //Check if there is a space at the first character. 
       try { 
        for(;;) { //Loop until we find a useable character 
         char c = txt.charAt(strt); 
          if (c == ' ' || c == '\t' || c == '\n' || c == '\r'){ 
          strt++; //Go to the next character if there is a space 
          } else { 
          break; //Found a character (not a space, tab or linebreak) - break the loop 
         } 
        } 
       }catch(IndexOutOfBoundsException e) { 
        Log.e("", e.getMessage()); 
        break; 
       } 

       //Make sure fin isnt less than strt 
       if(strt > fin) { fin = strt; } 

       //Now we search for the end of the word 
       //Loop until we find a space at the end of a word 
       try { 
        for(;;) { 
         char c = txt.charAt(fin); 
         if(c != ' ' && c != '\t' && c != '\n' && c != '\r') { 
          fin++; //Didn't find whitespace here, keep looking 
         } else { 
          break; //Now we found whitespace, end of a word 
         } 
        } 
        break; 
       } catch (IndexOutOfBoundsException e) { 
        //If this happens it should mean it just reached the end of the document. 
        Log.e("", "End of doc? : " + e.getMessage()); 
        break; 
       } 
      } 

      Log.d("", "It took " + String.valueOf(System.currentTimeMillis() - findStartPosTime) + " milliseconds to find a word"); 

      //Make sure fin isnt less that start, again 
      if(strt > fin) { fin = strt; } 

      //Debug time, how long it took to find a word 
      long matchTime = System.currentTimeMillis(); 

      //Found a word, see if it matches a word in our string[] 
      try { 
       for(String mStruct : mStructures) { 
        if(String.valueOf(txt.subSequence(strt, fin)).equals(mStruct)) { 
         //highlight 
         Spannable s = (Spannable) txt; 
         s.setSpan(new ForegroundColorSpan(Color.RED), strt, fin, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
         //Can someone explain why this is still setting the spannable to the main editable??? 
         //It should be set to txt right??? 

         break; 

        } else { 
         /*Spannable s = (Spannable) txt; 
         s.setSpan(new ForegroundColorSpan(Color.BLACK), strt, fin, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
         txt.removeSpan(s);*/ 
        } 
       } 

      }catch (IndexOutOfBoundsException e) { 
       e.printStackTrace(); 
       Log.e("", "word match error: " + e.getMessage()); 
      } 

      //Finally set strt to fin and start again! 
      strt = fin; 
      Log.d("", "match a word time " + String.valueOf(System.currentTimeMillis() - matchTime) + " milliseconds"); 
     }//end main while loop 

     Log.d("", "Syntax Highlight Finished in " + (System.currentTimeMillis() - syntime) + " milliseconds"); 
     mTextChanged = false; 
    } 


} 

「結構」 資源(php.xml)

<?xml version="1.0" encoding="utf-8"?> 
    <resources> 
     <string-array name="structures"> 
      <item>if</item> 
      <item>else</item> 
      <item>else if</item> 
      <item>while</item> 
      <item>do-while</item> 
      <item>for</item> 
      <item>foreach</item> 
      <item>break</item> 
      <item>continue</item> 
      <item>switch</item> 
      <item>declare</item> 
      <item>return</item> 
      <item>require</item> 
      <item>include</item> 
      <item>require_once</item> 
      <item>include_once</item> 
      <item>goto</item> 
     </string-array> 

</resources> 

任何人有任何建議,如何使搜索更快?我知道我有很多循環,但我不知道如何去做。

非常感謝!

+0

兩個提示讓你去:詞法分析(大狗使用什麼)和正則表達式(基本上是什麼詞法分析) – riwalk

+0

由於這個問題是相當本地化的,基本上是一個codereview ,我覺得它屬於codereview.SE並相應投票。 – vzwick

回答

1

你可以將字符串分割成你在那裏的分隔符而不是看每個字符嗎?這會加速一些。 (String.split())