From 84ab4d481ce56991a6635e87c5f000b056411087 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Mon, 26 Feb 2018 19:52:47 +0800 Subject: [PATCH] chore: find and replace --- app/build.gradle | 4 +- .../ui/edit/editor/CodeEditor.java | 94 ++++++++++++------- app/src/main/res/values/strings.xml | 1 + .../java/com/stardust/util/TextUtils.java | 91 ++++++++++++++++++ 4 files changed, 155 insertions(+), 35 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b5b9b046..d010d142 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.stardust.scriptdroid" minSdkVersion 17 targetSdkVersion 23 - versionCode 254 - versionName "3.1.0 Alpha4" + versionCode 255 + versionName "3.1.0 Alpha5" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java index b298062c..0637399f 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java @@ -4,12 +4,15 @@ import android.content.Context; import android.graphics.Canvas; import android.support.design.widget.Snackbar; import android.util.AttributeSet; +import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; +import com.android.dx.util.IntList; import com.stardust.autojs.script.JsBeautifier; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.ui.edit.theme.Theme; import com.stardust.util.ClipboardUtil; +import com.stardust.util.TextUtils; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,9 +46,6 @@ public class CodeEditor extends HVScrollView { } - private CharSequence mReplacement = ""; - private String mKeywords; - private int mFoundIndex = -1; private CodeEditText mCodeEditText; private TextViewRedoUndo mTextViewRedoUndo; private JavaScriptHighlighter mJavaScriptHighlighter; @@ -53,6 +53,12 @@ public class CodeEditor extends HVScrollView { private JsBeautifier mJsBeautifier; private MaterialDialog mProcessDialog; + + private CharSequence mReplacement = ""; + private String mKeywords; + private Matcher mMatcher; + private int mFoundIndex = -1; + public CodeEditor(Context context) { super(context); init(); @@ -206,23 +212,68 @@ public class CodeEditor extends HVScrollView { mTextViewRedoUndo.redo(); } + public void find(String keywords, boolean usingRegex) { + if (usingRegex) { + mMatcher = Pattern.compile(keywords).matcher(mCodeEditText.getText()); + mKeywords = null; + } else { + mKeywords = keywords; + mMatcher = null; + } + findNext(); + } + + public void replace(String keywords, String replacement, boolean usingRegex) { + mReplacement = replacement == null ? "" : replacement; + find(keywords, usingRegex); + } + + public void replaceAll(String keywords, String replacement, boolean usingRegex) { + if (!usingRegex) { + keywords = Pattern.quote(keywords); + } + String text = mCodeEditText.getText().toString(); + text = text.replaceAll(keywords, replacement); + setText(text); + } public void findNext() { - Matcher matcher = Pattern.compile(mKeywords).matcher(mCodeEditText.getText()); - if (!matcher.find(mFoundIndex + 1)) { - return; + int foundIndex; + if (mMatcher == null) { + if (mKeywords == null) + return; + foundIndex = TextUtils.indexOf(mCodeEditText.getText(), mKeywords, mFoundIndex + 1); + if (foundIndex >= 0) + mCodeEditText.setSelection(foundIndex, foundIndex + mKeywords.length()); + } else if (mMatcher.find(mFoundIndex + 1)) { + foundIndex = mMatcher.start(); + mCodeEditText.setSelection(foundIndex, foundIndex + mMatcher.group().length()); + } else { + foundIndex = -1; + } + if (foundIndex < 0 && mFoundIndex >= 0) { + mFoundIndex = -1; + findNext(); + } else { + mFoundIndex = foundIndex; } - mFoundIndex = matcher.start(); - mCodeEditText.setSelection(mFoundIndex, mFoundIndex + mKeywords.length()); } public void findPrev() { - // FIXME: 2018/2/21 lastIndexOf不支持正则 + if (mMatcher != null){ + Toast.makeText(getContext(), R.string.error_regex_find_prev, Toast.LENGTH_SHORT).show(); + return; + } + int len = mCodeEditText.getText().length(); if (mFoundIndex <= 0) { - mFoundIndex = mCodeEditText.getText().length(); + mFoundIndex = len; } int index = mCodeEditText.getText().toString().lastIndexOf(mKeywords, mFoundIndex - 1); if (index < 0) { + if (mFoundIndex != len) { + mFoundIndex = len; + findPrev(); + } return; } mFoundIndex = index; @@ -250,29 +301,6 @@ public class CodeEditor extends HVScrollView { }); } - public void find(String keywords, boolean usingRegex) { - if (usingRegex) { - mKeywords = keywords; - } else { - mKeywords = Pattern.quote(keywords); - } - mFoundIndex = -1; - findNext(); - } - - public void replace(String keywords, String replacement, boolean usingRegex) { - mReplacement = replacement == null ? "" : replacement; - find(keywords, usingRegex); - } - - public void replaceAll(String keywords, String replacement, boolean usingRegex) { - if (!usingRegex) { - keywords = Pattern.quote(keywords); - } - String text = mCodeEditText.getText().toString(); - text = text.replaceAll(keywords, replacement); - setText(text); - } public void insert(String insertText) { int selection = Math.max(mCodeEditText.getSelectionStart(), 0); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2714bf7..aae36b5e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -348,4 +348,5 @@ 字体大小 预览 字体大小: %d + 正则表达式不能向前查找 diff --git a/common/src/main/java/com/stardust/util/TextUtils.java b/common/src/main/java/com/stardust/util/TextUtils.java index 644f085d..c077ec87 100644 --- a/common/src/main/java/com/stardust/util/TextUtils.java +++ b/common/src/main/java/com/stardust/util/TextUtils.java @@ -55,4 +55,95 @@ public class TextUtils { } return -1; } + + public static int indexOf(CharSequence source, + CharSequence target, + int fromIndex) { + if (source instanceof String && target instanceof String) { + return ((String) source).indexOf((String) target); + } + if (fromIndex >= source.length()) { + return (target.length() == 0 ? source.length() : -1); + } + if (fromIndex < 0) { + fromIndex = 0; + } + if (target.length() == 0) { + return fromIndex; + } + + char first = target.charAt(0); + int max = (source.length() - target.length()); + + for (int i = fromIndex; i <= max; i++) { + /* Look for first character. */ + if (source.charAt(i) != first) { + while (++i <= max && source.charAt(i) != first) ; + } + + /* Found first character, now look at the rest of v2 */ + if (i <= max) { + int j = i + 1; + int end = j + target.length() - 1; + for (int k = 1; j < end && source.charAt(j) + == target.charAt(k); j++, k++) + ; + + if (j == end) { + /* Found whole string. */ + return i; + } + } + } + return -1; + } + + public static int lastIndexOf(CharSequence source, + CharSequence target, + int fromIndex) { + if (source instanceof String && target instanceof String) { + return ((String) source).lastIndexOf((String) target); + } + /* + * Check arguments; return immediately where possible. For + * consistency, don't check for null str. + */ + int rightIndex = source.length() - target.length(); + if (fromIndex < 0) { + return -1; + } + if (fromIndex > rightIndex) { + fromIndex = rightIndex; + } + /* Empty string always matches. */ + if (target.length() == 0) { + return fromIndex; + } + + int strLastIndex = target.length() - 1; + char strLastChar = target.charAt(strLastIndex); + int min = target.length() - 1; + int i = min + fromIndex; + + startSearchForLastChar: + while (true) { + while (i >= min && source.charAt(i) != strLastChar) { + i--; + } + if (i < min) { + return -1; + } + int j = i - 1; + int start = j - (target.length() - 1); + int k = strLastIndex - 1; + + while (j > start) { + if (source.charAt(j--) != target.charAt(k--)) { + i--; + continue startSearchForLastChar; + } + } + return start + 1; + } + } } \ No newline at end of file