正则匹配替换成com.google.re2j

自带的正则匹配超时无法取消
This commit is contained in:
kunfei 2022-10-17 16:52:20 +08:00
parent 99a89039c8
commit 6d349e1eab
4 changed files with 29 additions and 59 deletions

View File

@ -212,6 +212,9 @@ dependencies {
//implementation('com.github.gedoor:rhino-android:1.8') //implementation('com.github.gedoor:rhino-android:1.8')
implementation(fileTree(dir: 'lib', include: ['rhino-*.jar'])) implementation(fileTree(dir: 'lib', include: ['rhino-*.jar']))
//,android自带的正则匹配出现超时问题无法处理
implementation('com.google.re2j:re2j:1.7')
// //
implementation('com.squareup.okhttp3:okhttp:4.10.0') implementation('com.squareup.okhttp3:okhttp:4.10.0')
implementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar'])) implementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar']))

View File

@ -100,10 +100,9 @@ data class BookChapter(
if (item.pattern.isNotEmpty()) { if (item.pattern.isNotEmpty()) {
try { try {
val mDisplayTitle = if (item.isRegex) { val mDisplayTitle = if (item.isRegex) {
displayTitle.replace( displayTitle.replaceRegex(
item.pattern.toRegex(), item.pattern,
item.replacement, item.replacement
item.getValidTimeoutMillisecond()
) )
} else { } else {
displayTitle.replace(item.pattern, item.replacement) displayTitle.replace(item.pattern, item.replacement)

View File

@ -9,7 +9,7 @@ import io.legado.app.data.entities.ReplaceRule
import io.legado.app.exception.RegexTimeoutException import io.legado.app.exception.RegexTimeoutException
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.ReadBookConfig 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.stackTraceStr
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
@ -134,17 +134,16 @@ class ContentProcessor private constructor(
return contents return contents
} }
suspend fun replaceContent(content: String): String { fun replaceContent(content: String): String {
var mContent = content var mContent = content
mContent = mContent.lines().joinToString("\n") { it.trim() } mContent = mContent.lines().joinToString("\n") { it.trim() }
getContentReplaceRules().forEach { item -> getContentReplaceRules().forEach { item ->
if (item.pattern.isNotEmpty()) { if (item.pattern.isNotEmpty()) {
try { try {
mContent = if (item.isRegex) { mContent = if (item.isRegex) {
mContent.replace( mContent.replaceRegex(
item.pattern.toRegex(), item.pattern,
item.replacement, item.replacement
item.getValidTimeoutMillisecond()
) )
} else { } else {
mContent.replace(item.pattern, item.replacement) mContent.replace(item.pattern, item.replacement)

View File

@ -1,64 +1,33 @@
package io.legado.app.utils package io.legado.app.utils
import android.util.Log import android.util.Log
import androidx.core.os.postDelayed import com.google.re2j.Pattern
import com.script.SimpleBindings import com.script.SimpleBindings
import io.legado.app.constant.AppConst 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 { fun CharSequence.replaceRegex(regex: String, replacement: String): String {
val charSequence = this@replace val charSequence = this
val isJs = replacement.startsWith("@js:") val isJs = replacement.startsWith("@js:")
val replacement1 = if (isJs) replacement.substring(4) else replacement val replacement1 = if (isJs) replacement.substring(4) else replacement
return suspendCancellableCoroutine { block -> val pattern = Pattern.compile(regex)
val coroutine = Coroutine.async { val matcher = pattern.matcher(charSequence)
try { val stringBuffer = StringBuffer()
val pattern = regex.toPattern() while (matcher.find()) {
val matcher = pattern.matcher(charSequence) if (isJs) {
val stringBuffer = StringBuffer() val bindings = SimpleBindings()
while (matcher.find()) { bindings["result"] = matcher.group()
if (isJs) { val jsResult =
val bindings = SimpleBindings() AppConst.SCRIPT_ENGINE.eval(replacement1, bindings).toString()
bindings["result"] = matcher.group() matcher.appendReplacement(stringBuffer, jsResult)
val jsResult = } else {
AppConst.SCRIPT_ENGINE.eval(replacement1, bindings).toString() matcher.appendReplacement(stringBuffer, replacement1)
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()
}
}
}
} }
} }
matcher.appendTail(stringBuffer)
Log.e("regex", "end")
return stringBuffer.toString()
} }