diff --git a/app/build.gradle b/app/build.gradle index 465f241f8..293991271 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -212,6 +212,9 @@ dependencies { //implementation('com.github.gedoor:rhino-android:1.8') implementation(fileTree(dir: 'lib', include: ['rhino-*.jar'])) + //正则匹配,android自带的正则匹配出现超时问题无法处理 + implementation('com.google.re2j:re2j:1.7') + //网络 implementation('com.squareup.okhttp3:okhttp:4.10.0') implementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar'])) diff --git a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt index ab840ce89..c58ace49c 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt @@ -100,10 +100,9 @@ data class BookChapter( if (item.pattern.isNotEmpty()) { try { val mDisplayTitle = if (item.isRegex) { - displayTitle.replace( - item.pattern.toRegex(), - item.replacement, - item.getValidTimeoutMillisecond() + displayTitle.replaceRegex( + item.pattern, + item.replacement ) } else { displayTitle.replace(item.pattern, item.replacement) diff --git a/app/src/main/java/io/legado/app/help/book/ContentProcessor.kt b/app/src/main/java/io/legado/app/help/book/ContentProcessor.kt index 615f5e6fc..f1b118c84 100644 --- a/app/src/main/java/io/legado/app/help/book/ContentProcessor.kt +++ b/app/src/main/java/io/legado/app/help/book/ContentProcessor.kt @@ -9,7 +9,7 @@ import io.legado.app.data.entities.ReplaceRule import io.legado.app.exception.RegexTimeoutException import io.legado.app.help.config.AppConfig import io.legado.app.help.config.ReadBookConfig -import io.legado.app.utils.replace +import io.legado.app.utils.replaceRegex import io.legado.app.utils.stackTraceStr import io.legado.app.utils.toastOnUi import kotlinx.coroutines.CancellationException @@ -134,17 +134,16 @@ class ContentProcessor private constructor( return contents } - suspend fun replaceContent(content: String): String { + fun replaceContent(content: String): String { var mContent = content mContent = mContent.lines().joinToString("\n") { it.trim() } getContentReplaceRules().forEach { item -> if (item.pattern.isNotEmpty()) { try { mContent = if (item.isRegex) { - mContent.replace( - item.pattern.toRegex(), - item.replacement, - item.getValidTimeoutMillisecond() + mContent.replaceRegex( + item.pattern, + item.replacement ) } else { mContent.replace(item.pattern, item.replacement) diff --git a/app/src/main/java/io/legado/app/utils/RegexExtensions.kt b/app/src/main/java/io/legado/app/utils/RegexExtensions.kt index f1a4a300f..467d8b3ca 100644 --- a/app/src/main/java/io/legado/app/utils/RegexExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/RegexExtensions.kt @@ -1,64 +1,33 @@ package io.legado.app.utils import android.util.Log -import androidx.core.os.postDelayed +import com.google.re2j.Pattern import com.script.SimpleBindings import io.legado.app.constant.AppConst -import io.legado.app.exception.RegexTimeoutException -import io.legado.app.help.CrashHandler -import io.legado.app.help.coroutine.Coroutine -import kotlinx.coroutines.suspendCancellableCoroutine -import splitties.init.appCtx -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException - -private val handler by lazy { buildMainHandler() } /** * 带有超时检测的正则替换 */ -suspend fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String { - val charSequence = this@replace +fun CharSequence.replaceRegex(regex: String, replacement: String): String { + val charSequence = this val isJs = replacement.startsWith("@js:") val replacement1 = if (isJs) replacement.substring(4) else replacement - return suspendCancellableCoroutine { block -> - val coroutine = Coroutine.async { - try { - val pattern = regex.toPattern() - val matcher = pattern.matcher(charSequence) - val stringBuffer = StringBuffer() - while (matcher.find()) { - if (isJs) { - val bindings = SimpleBindings() - bindings["result"] = matcher.group() - val jsResult = - AppConst.SCRIPT_ENGINE.eval(replacement1, bindings).toString() - matcher.appendReplacement(stringBuffer, jsResult) - } else { - matcher.appendReplacement(stringBuffer, replacement1) - } - } - matcher.appendTail(stringBuffer) - Log.e("regex", "end") - block.resume(stringBuffer.toString()) - } catch (e: Exception) { - block.resumeWithException(e) - } - } - handler.postDelayed(timeout) { - if (coroutine.isActive) { - val timeoutMsg = "替换超时,3秒后还未结束将重启应用\n替换规则$regex\n替换内容:${this}" - val exception = RegexTimeoutException(timeoutMsg) - block.cancel(exception) - appCtx.longToastOnUi(timeoutMsg) - CrashHandler.saveCrashInfo2File(exception) - handler.postDelayed(3000) { - if (coroutine.isActive) { - appCtx.restart() - } - } - } + val pattern = Pattern.compile(regex) + val matcher = pattern.matcher(charSequence) + val stringBuffer = StringBuffer() + while (matcher.find()) { + if (isJs) { + val bindings = SimpleBindings() + bindings["result"] = matcher.group() + val jsResult = + AppConst.SCRIPT_ENGINE.eval(replacement1, bindings).toString() + matcher.appendReplacement(stringBuffer, jsResult) + } else { + matcher.appendReplacement(stringBuffer, replacement1) } } + matcher.appendTail(stringBuffer) + Log.e("regex", "end") + return stringBuffer.toString() }