正则匹配替换成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(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']))

View File

@ -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)

View File

@ -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)

View File

@ -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()
}