#android #optimization #syntax-highlighting
#Android #оптимизация #подсветка синтаксиса
Вопрос:
Я решил, что должен написать свой собственный подсветку синтаксиса. Пока это работает, но в режиме реального времени (вы вводите текст, он выделяется) и работает медленно.
Я попытаюсь объяснить, как это работает. Каждый раз, когда пользователь вводит что-то в EditText, он запускает подсветку (через TextWatcher). Подсветка выполняет поиск по тексту, пока не найдет начало слова, а затем выполняет поиск, пока не найдет конец того же слова. Как только он находит слово, он выполняет поиск по массиву ключевых слов, и если он находит совпадение, он устанавливает spannable в этом месте. Он продолжает цикл, пока не дойдет до конца документа.
Опять же, это работает до сих пор (просто пробую эту идею, прежде чем продолжить этот метод), но это так медленно. Иногда для просмотра нескольких строк может потребоваться более секунды. Это замедляет скорость отображения текста в 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 != ' ' amp;amp; c != 't' amp;amp; c != 'n' amp;amp; 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 amp;amp; 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 != ' ' amp;amp; c != 't' amp;amp; c != 'n' amp;amp; 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>
У кого-нибудь есть какие-либо предложения, как ускорить этот поиск? Я знаю, что у меня много циклов, но я не уверен, как еще это сделать.
Большое спасибо!
Комментарии:
1. Две подсказки, которые помогут вам: лексический анализ (то, что используют большие собаки) и регулярные выражения (по сути, что такое лексический анализ)
2. Поскольку этот вопрос довольно локализован и в основном представляет собой запрос на codereview, я чувствую, что он относится к codereview. SE и проголосовали соответствующим образом.
Ответ №1:
Можете ли вы разделить строку на имеющиеся у вас разделители, а не смотреть на каждый символ? Это немного ускорило бы процесс. (String.split())