pull/2457/head
kunfei 3 years ago
parent a3a3c53199
commit 2eb138646d
  1. 3
      app/build.gradle
  2. 6
      app/src/main/java/io/legado/app/data/entities/BookChapter.kt
  3. 7
      app/src/main/java/io/legado/app/help/book/ContentProcessor.kt
  4. 74
      app/src/main/java/io/legado/app/utils/RegexExtensions.kt

@ -212,9 +212,6 @@ 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']))

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

@ -9,7 +9,6 @@ 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.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
@ -141,10 +140,10 @@ class ContentProcessor private constructor(
if (item.pattern.isNotEmpty()) { if (item.pattern.isNotEmpty()) {
try { try {
mContent = if (item.isRegex) { mContent = if (item.isRegex) {
mContent.replaceRegex( mContent.replace(
item.pattern, item.pattern.toRegex(),
item.replacement item.replacement
).getOrThrow() )
} else { } else {
mContent.replace(item.pattern, item.replacement) mContent.replace(item.pattern, item.replacement)
} }

@ -1,34 +1,64 @@
package io.legado.app.utils package io.legado.app.utils
import com.google.re2j.Pattern import android.util.Log
import androidx.core.os.postDelayed
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() }
/** /**
* 带有js功能的正则替换 * 带有超时检测的正则替换
* 采用com.google.re2j.Pattern,不会导致无限执行
*/ */
fun CharSequence.replaceRegex(regex: String, replacement: String): Result<String> { suspend fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String {
return kotlin.runCatching { 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)
stringBuffer.toString()
} }
} }

Loading…
Cancel
Save