From 42b6c694da63d0b0c4bd1b33916745152eebb75f Mon Sep 17 00:00:00 2001 From: bushixuanqi <2208877960@qq.com> Date: Sun, 4 Jul 2021 01:26:17 +0800 Subject: [PATCH] =?UTF-8?q?0.=20=E6=96=B0=E5=A2=9E=E4=B8=93=E9=97=A8?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E5=88=87=E5=88=86=E5=90=84=E7=A7=8D=E8=A7=84?= =?UTF-8?q?=E5=88=99=E7=9A=84=E7=B1=BB=EF=BC=8C=E5=88=86=E8=A7=A3=E5=AE=8C?= =?UTF-8?q?=E6=89=80=E6=9C=89=E8=A7=84=E5=88=99=E5=90=8E=E6=89=8D=E5=88=87?= =?UTF-8?q?=E7=89=87=EF=BC=8C=E5=85=B6=E4=BD=99=E6=93=8D=E4=BD=9C=E9=83=BD?= =?UTF-8?q?=E5=8F=AA=E6=94=B9=E5=8F=98=E5=8F=98=E9=87=8F=E6=8C=87=E5=90=91?= =?UTF-8?q?=E8=A7=84=E5=88=99=E5=AD=97=E7=AC=A6=E4=B8=B2=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E3=80=82=E6=9A=82=E6=97=B6=E5=8F=AA=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E5=A4=84=E7=90=86=E4=B8=89=E5=A4=A7=E8=A7=84=E5=88=99?= =?UTF-8?q?=E7=9A=84=E2=80=9C&&=E2=80=9D=E3=80=81=E2=80=9C||=E2=80=9D?= =?UTF-8?q?=EF=BC=8C=E2=80=9C%%=E2=80=9D=E3=80=81=E2=80=9C@=E2=80=9D?= =?UTF-8?q?=E5=88=87=E5=88=86=EF=BC=8C=E4=BB=A5=E5=90=8E=E5=B0=86=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E5=88=B0=E5=85=A8=E9=83=A8=E8=A7=A3=E6=9E=90=E8=A7=84?= =?UTF-8?q?=E5=88=99=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进jsonPath,jsoup,xpath中的规则切分方法,允许查询规则的正则或字符串中存在“&&”,“||”,“%%”,“@”而不切错。 /** * 改进解析方法 * 解决阅读”&&“、”||“与jsonPath支持的”&&“、”||“之间的冲突 * 解决{$.rule}形式规则可能匹配错误的问题,旧规则用正则解析内容含‘}’的json文本时,用规则中的字段去匹配这种内容时,会匹配错误.现改用平衡嵌套方法解决这个问题 * */ 1. 加强AnalyzeByJSoup中的索引写法 /** * 1.支持阅读原有写法,':'分隔索引,!或.表示筛选方式,索引可为负数 * * 例如 tag.div.-1:10:2 或 tag.div!0:3 * * 2. 支持与jsonPath类似的[]索引写法 * * 格式形如 [it,it,。。。] 或 [!it,it,。。。] 其中[!开头表示筛选方式为排除,it为单个索引或区间。 * * 区间格式为 start:end 或 start:end:step,其中start为0可省略,end为-1可省略。 * * 索引,区间两端及间隔都支持负数 * * 例如 tag.div[-1, 3:-2:-10, 2] * * 特殊用法 tag.div[-1:0] 可在任意地方让列表反向 * * */ ------------------- 已测试过各种“&&”、“||”,“%%”切分的规则及两者索引写法,没发现大问题,坤飞大大可以再测试看看 --- .../model/analyzeRule/AnalyzeByJSonPath.kt | 2 +- .../app/model/analyzeRule/AnalyzeByJSoup.kt | 171 ++++++++++-------- 2 files changed, 93 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt index e9abb23b2..63e02ec8c 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt @@ -25,7 +25,7 @@ class AnalyzeByJSonPath(json: Any) { /** * 改进解析方法 * 解决阅读”&&“、”||“与jsonPath支持的”&&“、”||“之间的冲突 - * 解决{$.rule}形式规则可能匹配错误的问题,旧规则正则解析内容含‘}’的json文本,用规则中的字段去匹配这种内容时,会匹配错误.现改用平衡嵌套方法解决这个问题 + * 解决{$.rule}形式规则可能匹配错误的问题,旧规则用正则解析内容含‘}’的json文本时,用规则中的字段去匹配这种内容时,会匹配错误.现改用平衡嵌套方法解决这个问题 * */ fun getString(rule: String): String? { if (rule.isEmpty()) return null diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt index 37e9bfd1c..6f45f9f21 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt @@ -184,108 +184,113 @@ class AnalyzeByJSoup(doc: Any) { } /** - * '.'开头表示选择元素,或'!'开头排除那些元素。两者都支持以索引列表按顺序指定元素列表 - * ':'分隔不同索引或区间 - * 区间格式为 start~end+step,其中start为0可省略,end为-1可省略。 + * 1.支持阅读原有写法,':'分隔索引,!或.表示筛选方式,索引可为负数 + * + * 例如 tag.div.-1:10:2 或 tag.div!0:3 + * + * 2. 支持与jsonPath类似的[]索引写法 + * + * 格式形如 [it,it,。。。] 或 [!it,it,。。。] 其中[!开头表示筛选方式为排除,it为单个索引或区间。 + * + * 区间格式为 start:end 或 start:end:step,其中start为0可省略,end为-1可省略。 + * * 索引,区间两端及间隔都支持负数 - * 例如 tag.div.-1:3~-2+-10:2 - * 特殊用法 tag.div.-1~0 可在任意地方让列表反向 + * + * 例如 tag.div[-1, 3:-2:-10, 2] + * + * 特殊用法 tag.div[-1:0] 可在任意地方让列表反向 + * * */ + fun findIndexSet( rule:String ): IndexSet { val indexSet = IndexSet() - val rus = rule.trim{ it <= ' '} - var last = rus.length - var step = 0 //区间步长,为0表示没设置区间 - var curInt: Int //当前数字 - var end = 0 //暂存区间结束数字 - - var range = false //true表示当前在区间开头,false表示当前在区间结尾 + var len = rus.length + var curInt: Int? //当前数字 var curMinus = false //当前数字是否为负 - var curEndMinus = false //当前区间右端数字是否为负 - var curStepMinus = false //当前区间间隔数字是否为负 - + val curList = mutableListOf() //当前数字区间 var l = "" //暂存数字字符串 - while (last --> 1 ){ //逆向遍历,至少有两位前置字符,如 p. + val head = rus[rus.length-1] == ']' //是否为常规索引写法 - val rl = rus[last] - if(rl == ' ' )continue //跳过空格 - if( rl in '0'..'9') l+= rl //将数值累接入临时字串中,遇到分界符才取出 - else if(rl == '-') curMinus = true - else if( rl in arrayOf('+','~','!','.',':')) { //分界符号 '+','~','!','.',':' + if(head){ //常规索引写法[index...] - when ( rl ) { + len-- //跳过尾部']' - '+' ->{ - curStepMinus = curMinus - step = l.toInt() //区间间隔数 - } + while (len-- > 0) { //逆向遍历,至少有一位前置字符,如 [ - '~' -> { - range = true - curEndMinus = curMinus + var rl = rus[len] + if (rl == ' ') continue //跳过空格 - if (l.isEmpty()) { - end = -1 //省略区间右端,设置为-1 - continue - } else end = l.toInt() - } + if (rl in '0'..'9') l += rl //将数值累接入临时字串中,遇到分界符才取出 + else if (rl == '-') curMinus = true + else { - else -> { + curInt = if (l.isEmpty()) null else if (curMinus) -l.toInt() else l.toInt() //当前数字 - curInt = if(l.isEmpty()) 0 /* 省略区间左端,设置为0 */ else if(curMinus) - l.toInt() else l.toInt() //区间左端数,省略则为最左边 + when (rl) { - indexSet.indexs.add( //压入以下值,为保证查找顺序,区间和单个索引都添加到同一集合 + ':' -> curList.add(curInt) //区间右端或区间间隔 - if ( range ) { + else -> { - range = false //重置 + indexSet.indexs.add( //压入以下值,为保证查找顺序,区间和单个索引都添加到同一集合 - if (curEndMinus) { - end = -end - curEndMinus = false //重置 - } + if(curList.isEmpty()) curInt!! //区间为空,表明当前是单个索引,单个索引不能空 - //没设置间隔时,间隔为1。将区间的三项数据压入,在获取到元素数量后再计算负数索引,并展开区间 - if( step == 0 ) Triple(curInt, end, 1) + else Triple(curInt, curList.last(), if(curList.size == 2) curList.first() else 1) //否则为区间,列表最后压入的是区间右端,若列表有两位则最先压入了间隔 - else { + ) - if (curStepMinus) { - step = -step - curStepMinus = false //重置 - } + if(rl == '!'){ + indexSet.split='!' + do{ rl = rus[--len] } while (len > 0 && rl == ' ')//跳过所有空格 + } - val stepx = step - step = 0 //重置 + if(rl == '[') return indexSet.apply { + beforeRule = rus.substring(0, len) + } //遇到索引边界,返回结果 - //将区间的三项数据压入,在获取到元素数量后再计算负数索引,并展开区间 - Triple(curInt, end, stepx) + if(rl != ',') break //非索引结构,跳出 - } + } + } - }else curInt //压入单个索引,在获取到元素数量后再计算负数索引 + l = "" //清空 + curMinus = false //重置 + } + } + } else while (len --> 1) { //阅读原本写法,逆向遍历,至少两位前置字符,如 p. - ) + val rl = rus[len] + if (rl == ' ') continue //跳过空格 - if( rl == '!' || rl == '.' ) return indexSet.apply{ - split = rl - beforeRule = rus.substring(0, last) - } + if (rl in '0'..'9') l += rl //将数值累接入临时字串中,遇到分界符才取出 + else if (rl == '-') curMinus = true + else { + + if(rl == '!' || rl == '.' || rl == ':') { //分隔符或起始符 + + indexSet.indexDefault.add(if (curMinus) -l.toInt() else l.toInt()) // 当前数字追加到列表 + + if (rl != ':') return indexSet.apply { //rl == '!' || rl == '.' + split = rl + beforeRule = rus.substring(0, len) } - } + + }else break //非索引结构,跳出循环 + l = "" //清空 curMinus = false //重置 } - else break - } - return indexSet.apply{ beforeRule = rus } //非索引格式 + return indexSet.apply{ + split = ' ' + beforeRule = rus } //非索引格式 } /** @@ -321,7 +326,7 @@ class AnalyzeByJSoup(doc: Any) { for (pcInt in indexSet) elements[pcInt] = null - elements.removeAll(listOf(null)) //测试过,这样就能把全部null元素删除 + elements.removeAll(listOf(null)) //测试过,这样就行 }else if(filterType == '.'){ //选择 @@ -412,38 +417,46 @@ class AnalyzeByJSoup(doc: Any) { return textS } - data class IndexSet(var split:Char = ' ', + data class IndexSet(var split:Char = '.', var beforeRule:String = "", + val indexDefault:MutableList = mutableListOf(), val indexs:MutableList = mutableListOf()){ fun getIndexs(len:Int): MutableSet { val indexSet = mutableSetOf() - val lastIndexs = indexs.size - 1 + val lastIndexs = (indexDefault.size - 1).takeIf { it !=-1 } ?: indexs.size -1 + + + if(indexs.isEmpty())for (ix in lastIndexs downTo 0 ){ //indexs为空,表明是非[]式索引,集合是逆向遍历插入的,所以这里也逆向遍历,好还原顺序 + + val it = indexDefault[ix] + if(it in 0 until len) indexSet.add(it) //将正数不越界的索引添加到集合 + else if(it < 0 && len >= -it) indexSet.add(it + len) //将负数不越界的索引添加到集合 - for (ix in lastIndexs downTo 0 ){ //逆向遍历,还原顺序 + }else for (ix in lastIndexs downTo 0 ){ //indexs不空,表明是[]式索引,集合是逆向遍历插入的,所以这里也逆向遍历,好还原顺序 if(indexs[ix] is Triple<*, *, *>){ //区间 - var (start, end, step) = indexs[ix] as Triple //还原储存时的类型 + val (startx, endx, stepx) = indexs[ix] as Triple //还原储存时的类型 - if (start >= 0) { - if (start >= len) start = len - 1 //右端越界,设置为最大索引 - } else start = if (-start <= len) len + start /* 将负索引转正 */ else 0 //左端越界,设置为最小索引 + val start = if (startx == null) 0 //左端省略表示0 + else if (startx >= 0) if (startx < len) startx else len - 1 //右端越界,设置为最大索引 + else if (-startx <= len) len + startx /* 将负索引转正 */ else 0 //左端越界,设置为最小索引 - if (end >= 0) { - if (end >= len) end = len - 1 //右端越界,设置为最大索引 - } else end = if (-end <= len) len + end /* 将负索引转正 */ else 0 //左端越界,设置为最小索引 + val end = if (endx == null) len - 1 //右端省略表示 len - 1 + else if (endx >= 0) if (endx < len) endx else len - 1 //右端越界,设置为最大索引 + else if (-endx <= len) len + endx /* 将负索引转正 */ else 0 //左端越界,设置为最小索引 - if (start == end || step >= len) { //两端相同,区间里只有一个数。或间隔过大,区间实际上仅有首位 + if (start == end || stepx >= len) { //两端相同,区间里只有一个数。或间隔过大,区间实际上仅有首位 - indexSet.add(start) + indexSet.add(stepx) continue } - step = if (step > 0) step else if (-step < len) step + len else 1 //最小正数间隔为1 + val step = if (stepx > 0) stepx else if (-stepx < len) stepx + len else 1 //最小正数间隔为1 //将区间展开到集合中,允许列表反向。 indexSet.addAll(if (end > start) start..end step step else start downTo end step step)