diff --git a/app/src/main/java/io/legado/app/constant/AppPattern.kt b/app/src/main/java/io/legado/app/constant/AppPattern.kt index c38e1359c..d4a3e4a19 100644 --- a/app/src/main/java/io/legado/app/constant/AppPattern.kt +++ b/app/src/main/java/io/legado/app/constant/AppPattern.kt @@ -8,8 +8,8 @@ object AppPattern { Pattern.compile("([\\w\\W]*?|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE) val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") - //只匹配格式化后的图片 - val imgPattern: Pattern = Pattern.compile("") + //匹配格式化后的图片格式 + val imgPattern: Pattern = Pattern.compile("]+)\">") val nameRegex = Regex("\\s+作\\s*者.*|\\s+\\S+\\s+著") val authorRegex = Regex("^.*?作\\s*者[::\\s]*|\\s+著") diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index e0ac417c9..0b44f78fd 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -130,7 +130,7 @@ class AnalyzeUrl( bindings["book"] = book //替换所有内嵌{{js}} - val url = analyze.innerRule("{{",2,2){ + val url = analyze.innerJsRule{ when(val jsEval = SCRIPT_ENGINE.eval(it, bindings)){ is String -> jsEval jsEval is Double && jsEval % 1.0 == 0.0 -> String.format("%.0f", jsEval) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/RuleAnalyzer.kt b/app/src/main/java/io/legado/app/model/analyzeRule/RuleAnalyzer.kt index 9813922be..2a0af6d28 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/RuleAnalyzer.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/RuleAnalyzer.kt @@ -32,11 +32,6 @@ class RuleAnalyzer(data: String, code: Boolean = false) { startX = 0 } - //返回剩余字段 - fun Remained(): String { - return queue.substring(pos) - } - /** * 从剩余字串中拉出一个字符串,直到但不包括匹配序列 * @param seq 查找的字符串 **区分大小写** @@ -51,20 +46,6 @@ class RuleAnalyzer(data: String, code: Boolean = false) { } else false } - /** - * 从剩余字串中拉出一个字符串,直到但不包括匹配序列 - * @param seq 查找的字符串 **区分大小写** - * @return 返回查找的字符串之前的匹配字段 - */ - fun consumeToString(seq: String): String { - start = pos //将处理到的位置设置为规则起点 - val offset = queue.indexOf(seq, pos) - return if (offset != -1) { - pos = offset - queue.substring(start, offset) - } else "" - } - /** * 从剩余字串中拉出一个字符串,直到但不包括匹配序列(匹配参数列表中一项即为匹配),或剩余字串用完。 * @param seq 匹配字符串序列 @@ -111,7 +92,7 @@ class RuleAnalyzer(data: String, code: Boolean = false) { } //其中js只要符合语法,就不用避开任何阅读关键字,自由发挥 - fun chompJsBalanced(innerType:Boolean = true,startPos:Int = pos): String { + fun chompJsBalanced(innerType:Boolean = true,startPos:Int = pos): Boolean { var pos = startPos //声明变量记录临时处理位置 var bracketsDepth = 0 //[]嵌套深度 @@ -179,13 +160,13 @@ class RuleAnalyzer(data: String, code: Boolean = false) { if( c == endChar && queue.regionMatches(pos, end, 0, end.length)) { this.pos = pos - return queue.substring(startPos + start.length, pos - end.length) //匹配到终点,返回结果 + return true } } else pos++ } while (bracketsDepth > 0) //拉出全部符合js语法的字段 - return "" + return false } @@ -330,7 +311,7 @@ class RuleAnalyzer(data: String, code: Boolean = false) { val next = if (queue[pos] == '[') ']' else ')' //平衡组末尾字符 if (!chompBalanced(queue[pos], next)) throw Error( - queue.substring(0,start) + "后未平衡" + queue.substring(0,start) + "后未平衡" ) //拉出一个筛选器,不平衡则报错 } while (end > pos) @@ -387,7 +368,7 @@ class RuleAnalyzer(data: String, code: Boolean = false) { val next = if (queue[pos] == '[') ']' else ')' //平衡组末尾字符 if (!chompBalanced(queue[pos], next)) throw Error( - queue.substring(0,start) + "后未平衡" + queue.substring(0,start) + "后未平衡" ) //拉出一个筛选器,不平衡则报错 } while (end > pos) @@ -403,19 +384,18 @@ class RuleAnalyzer(data: String, code: Boolean = false) { /** * 替换内嵌规则 - * @param inner 起始标志,如{$. 或 {{ + * @param inner 起始标志,如{$. * @param startStep 不属于规则部分的前置字符长度,如{$.中{不属于规则的组成部分,故startStep为1 - * @param endStep 不属于规则部分的后置字符长度,如}}长度为2 + * @param endStep 不属于规则部分的后置字符长度 * @param fr 查找到内嵌规则时,用于解析的函数 * * */ fun innerRule( - inner: String, - startStep: Int = 1, - endStep: Int = 1, - fr: (String) -> String? + inner: String, + startStep: Int = 1, + endStep: Int = 1, + fr: (String) -> String? ): String { - val st = StringBuilder() while (consumeTo(inner)) { //拉取成功返回true,ruleAnalyzes里的字符序列索引变量pos后移相应位置,否则返回false,且isEmpty为true @@ -436,6 +416,34 @@ class RuleAnalyzer(data: String, code: Boolean = false) { }.toString() } + /** + * 替换内嵌规则 + * @param fr 查找到内嵌规则时,用于解析的函数 + * + * */ + fun innerJsRule( + fr: (String) -> String? + ): String { + val st = StringBuilder() + + while (consumeTo("{{")) { //拉取成功返回true,ruleAnalyzes里的字符序列索引变量pos后移相应位置,否则返回false,且isEmpty为true + val posPre = pos //记录consumeTo匹配位置 + if (chompJsBalanced()) { + val frv = fr(queue.substring(posPre + 2, pos - 2)) + if (!frv.isNullOrEmpty()) { + st.append(queue.substring(startX, posPre) + frv) //压入内嵌规则前的内容,及内嵌规则解析得到的字符串 + startX = pos //记录下次规则起点 + continue //获取内容成功,继续选择下个内嵌规则 + } + } + pos += 2 //拉出字段不平衡,inner只是个普通字串,跳到此inner后继续匹配 + } + + return if(startX == 0) "" else st.apply { + append(queue.substring(startX)) + }.toString() + } + companion object { /** * 转义字符 diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt index cb74714ea..ca3643caa 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt @@ -12,6 +12,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.AppConfig import io.legado.app.help.ReadBookConfig +import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.ui.book.read.page.entities.TextChapter import io.legado.app.ui.book.read.page.entities.TextChar import io.legado.app.ui.book.read.page.entities.TextLine @@ -110,11 +111,11 @@ object ChapterProvider { isTitle, textPaint, srcList ) } - } else { + } else if (book.getImageStyle() != Book.imgStyleText) { content.replace(AppPattern.imgPattern.toRegex(), "\n\$0\n") .split("\n").forEach { text -> if (text.isNotBlank()) { - if(!text.startsWith("]*data-".toRegex())) "]*data-[^=]*= *\"([^\"])\"[^>]*>" - else "  ]*src *= *\"([^\"{]+(?:\\{(?:[^{}]|\\{[^{}]*\\})*\\})?)\"[^>]*>", Pattern.CASE_INSENSITIVE + if(keepImgHtml.matches("]*data-".toRegex())) { + hasDataType = true + "]*data-[^=]*= *\"([^\"])\"[^>]*>" + } + else { + hasDataType = false + "]*src *= *\"([^\"{]+(?:\\{(?:[^{}]|\\{[^{}]*\\})*\\})?)\"[^>]*>" + }, Pattern.CASE_INSENSITIVE ) val matcher = imgPattern.matcher(keepImgHtml) var appendPos = 0 if(matcher.find()){ - var url = matcher.group(1)!! - var pos = url.indexOf(',') - sb.append(keepImgHtml.substring(appendPos, matcher.start())) - sb.append( - "" - ) - appendPos = matcher.end() - if(pos == -1) { - while (matcher.find()) { - sb.append(keepImgHtml.substring(appendPos, matcher.start())) + if(hasDataType || matcher.group(1)!!.indexOf(',') == -1) { //图片无参 + + do{ + sb.append(keepImgHtml.substring(appendPos, matcher.start()).replace("\n","\n  ")) //非图片部分换行缩减 sb.append( "" ) appendPos = matcher.end() - } - }else{ - while (matcher.find()) { - url = matcher.group(1)!! - pos = url.indexOf(',') - sb.append(keepImgHtml.substring(appendPos, matcher.start())) + }while (matcher.find()) + + }else{ //图片有参 + + do{ + val url = matcher.group(1)!! + val pos = url.indexOf(',') + sb.append(keepImgHtml.substring(appendPos, matcher.start()).replace("\n","\n  ")) //非图片部分换行缩减 sb.append( "" ) appendPos = matcher.end() - } + }while(matcher.find()) + } } if (appendPos < keepImgHtml.length) { - sb.append(keepImgHtml.substring(appendPos, keepImgHtml.length)) + sb.append(keepImgHtml.substring(appendPos, keepImgHtml.length).replace("\n","\n  ")) //非图片部分换行缩减 } return sb.toString() }