独自の構文ハイライターを作成する必要があると判断しました。これまでのところ動作していますが、リアルタイムで(ハイライト表示)、遅いです。構文ハイライダーの最適化
どのように動作するか説明しようとします。ユーザーがEditTextに何かを入力するたびに、(TextWatcherを介して)ハイライターを実行します。ハイライターは、単語の先頭を見つけるまでテキストを検索し、同じ単語の終わりを見つけるまで検索します。単語を見つけたら、一連のキーワードを検索し、一致するものがあればその場所にスパナブルを設定します。ドキュメントの終わりに達するまで繰り返しループします。
もう一度、この方法を続ける前にこのアイデアを試してみてください。しかし、それは遅いです。いくつかの行をいくつかの行を通過するために何度かそれを取ることができます。 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>
誰もがどのように速く、この検索を行うために、任意の提案を持っている:
は、ここに私のEditTextの基本ですか?私はループがたくさんあることは知っていますが、それ以外の方法はわかりません。
ありがとうございます!
字句解析(大きな犬が使っていること)と正規表現(基本的に字句解析があります) – riwalk
この質問はかなりローカライズされており、基本的にcodereview私はそれがcodereview.SEに属するように感じ、それに応じて投票しました。 – vzwick