Update RuleAnalyzer.kt

简化部分规则,调整压入切分出的规则时的判断顺序,避免重复压入
pull/1099/head
bushixuanqi 3 years ago committed by GitHub
parent 610b4ac536
commit 9a00fb82da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 144
      app/src/main/java/io/legado/app/model/analyzeRule/RuleAnalyzer.kt

@ -8,7 +8,6 @@ class RuleAnalyzer(data: String) {
private var pos = 0 //处理到的位置 private var pos = 0 //处理到的位置
private var start = 0 //每次处理字段的开始 private var start = 0 //每次处理字段的开始
private var end:Int = queue.length //每次处理字段的终点
private var step:Int = 0 //分割字符的长度 private var step:Int = 0 //分割字符的长度
var elementsType = "" var elementsType = ""
@ -29,7 +28,7 @@ class RuleAnalyzer(data: String) {
} }
//剩余字串 //剩余字串
fun remainingString(): String { private fun remainingString(): String {
start = pos start = pos
pos = queue.length pos = queue.length
return queue.substring(start) return queue.substring(start)
@ -82,69 +81,73 @@ class RuleAnalyzer(data: String) {
return queue.regionMatches(pos, seq, 0, seq.length, ignoreCase = true) return queue.regionMatches(pos, seq, 0, seq.length, ignoreCase = true)
} }
/**
* 测试下个字符是否与序列中相应位置的字符相等
* @param seq 被检查的字符列表
* @return 相等就为 true 不相等则为 false
*/
fun matchesAny(vararg seq: Char): Boolean {
if (isEmpty) return false
for (c in seq) {
if (queue[pos] == c) {
return true
}
}
return false
}
/**
* 测试下个字符是否与参数列表里的序列存在匹配 不区分大小写
* @param seq 被不区分大小写检查的字符串列表
* @return 只要匹配就为 true 没有匹配则为 false
*/
fun matchesAny(vararg seq: String): Boolean {
for (s in seq) {
if (matches(s)) {
step = s.length
return true
}
}
return false
}
/** /**
* 从剩余字串中拉出一个字符串直到但不包括匹配序列或剩余字串用完 * 从剩余字串中拉出一个字符串直到但不包括匹配序列或剩余字串用完
* @param seq 分隔字符 **区分大小写** * @param seq 分隔字符 **区分大小写**
* @return 是否找到相应字段 * @return 是否找到相应字段
*/ */
fun consumeTo(seq: String,setStartPos:Boolean = true): Boolean { fun consumeTo(seq: String,setStartPos:Boolean = true): Boolean {
if(setStartPos)start = pos //将处理到的位置设置为规则起点 if(setStartPos)start = pos //将处理到的位置设置为规则起点
val offset = queue.indexOf(seq, pos) val offset = queue.indexOf(seq, pos)
return if (offset != -1) { return if (offset != -1) {
pos = offset pos = offset
true true
} else false } else false
}
/**
* 从剩余字串中拉出一个字符串直到且包括匹配序列匹配参数列表中一项即为匹配或剩余字串用完
* @param seq 匹配字符串序列
* @return 成功返回true并推移pos失败返回fasle而不推移pos
*/
fun consumeToAny(vararg seq:String): Boolean {
start = pos
while (!isEmpty) {
for (s in seq) {
if (matches(s)) {
step = s.length //间隔数
return true //匹配就返回 true
}
}
pos++ //逐个试探
}
pos = start //匹配失败,位置回退
return false
} }
/** /**
* 从剩余字串中拉出一个字符串直到但不包括匹配序列匹配参数列表中一项即为匹配或剩余字串用完 * 从剩余字串中拉出一个字符串直到但不包括匹配序列匹配参数列表中一项即为匹配或剩余字串用完
* @param f 消费函数返回true表示消费fasle表示不消费 * @param seq 匹配字符序列
* @param setStartPos 设置开始消费位置 * @return 匹配到的位置
* @return 消耗的字符串
*/ */
fun consumeToAny(setStartPos:Boolean = true, f:()->Boolean,): Boolean { private fun findToAny(vararg seq:Char): Int {
if(setStartPos)start = pos //将处理到的位置设置为规则起点
while (!isEmpty && !f()) { for (s in seq){
pos++
val offset = queue.indexOf(s, pos)
if (offset != -1) return offset //只要匹配到,就返回相应位置
} }
return !isEmpty
return -1
} }
//其中js只要符合语法,就不用避开任何阅读关键字,自由发挥 //其中js只要符合语法,就不用避开任何阅读关键字,自由发挥
fun chompJsBalanced(f: ((Char) -> Boolean?) = { fun chompJsBalanced(f: ((Char) -> Boolean?) = {
if ( it == '{' )true //开始嵌套一层 when (it) {
else if ( it == '}') false //闭合一层嵌套 '{' -> true //开始嵌套一层
else null '}' -> false //闭合一层嵌套
else -> null
}
} ): Boolean { } ): Boolean {
start = pos start = pos
var depth = 0 //嵌套深度 var depth = 0 //嵌套深度
@ -178,20 +181,20 @@ class RuleAnalyzer(data: String) {
} }
else if(regex && c == '/') { //正则的终点或[]平衡 else if(regex && c == '/') { //正则的终点或[]平衡
if(c == '/')regex = false//匹配正则终点 when (c) {
'/' -> regex = false//匹配正则终点
//为了保证当open为( 且 close 为 )时,正则中[(]或[)]的合法性。故对[]这对在任何规则中都平衡的成对符号做匹配。
// 注:正则里[(]、[)]、[{]、[}]都是合法的,所以只有[]必须平衡。
else if ( c == '[' )bracketsDepth++ //开始嵌套一层[] //为了保证当open为( 且 close 为 )时,正则中[(]或[)]的合法性。故对[]这对在任何规则中都平衡的成对符号做匹配。
else if ( c== ']') bracketsDepth-- //闭合一层嵌套[] // 注:正则里[(]、[)]、[{]、[}]都是合法的,所以只有[]必须平衡。
'[' -> bracketsDepth++ //开始嵌套一层[]
']' -> bracketsDepth-- //闭合一层嵌套[]
}
} }
if (commits || commit || regex || inSingleQuote || inDoubleQuote || inOtherQuote) continue //语法单元未匹配结束,直接进入下个循环 if (commits || commit || regex || inSingleQuote || inDoubleQuote || inOtherQuote) continue //语法单元未匹配结束,直接进入下个循环
val fn = f(c) val fn = f(c) ?: continue
if (fn == null) continue
if (fn) depth++ else depth-- //嵌套或者闭合 if (fn) depth++ else depth-- //嵌套或者闭合
}else { //转义字符 }else { //转义字符
@ -233,8 +236,7 @@ class RuleAnalyzer(data: String) {
if ( c == open )depth++ //开始嵌套一层 if ( c == open )depth++ //开始嵌套一层
else if ( c== close) depth-- //闭合一层嵌套 else if ( c== close) depth-- //闭合一层嵌套
else if(depth == 0 && f != null) { //处于默认嵌套中的非默认字符不需要平衡,仅depth为0时默认嵌套全部闭合,此字符才进行嵌套 else if(depth == 0 && f != null) { //处于默认嵌套中的非默认字符不需要平衡,仅depth为0时默认嵌套全部闭合,此字符才进行嵌套
val fn = f(c) val fn = f(c) ?: continue
if (fn == null) continue
if (fn) otherDepth++ else otherDepth-- if (fn) otherDepth++ else otherDepth--
} }
@ -257,24 +259,28 @@ class RuleAnalyzer(data: String) {
*/ */
tailrec fun splitRule(vararg split: String): Array<String>{ //首段匹配,elementsType为空 tailrec fun splitRule(vararg split: String): Array<String>{ //首段匹配,elementsType为空
if (!consumeToAny { matchesAny(* split) }) return arrayOf(queue) //未找到分隔符 if(split.size == 1) {
elementsType = split[0] //设置分割字串
step = elementsType.length //设置分隔符长度
return splitRule(arrayOf()) //仅一个分隔字串时,直接二段解析更快
}else if (!consumeToAny(* split)) return arrayOf(queue) //未找到分隔符
end = pos val st = findToAny( '(','[' ) //查找筛选器
val st = if( consumeToAny(false){ matchesAny( '(','[' ) } )pos else -1 //查找筛选器
pos = end
if(st == -1) { if(st == -1) {
var rule = arrayOf(queue.substring(0, pos)) //压入分隔的首段规则到数组 var rule = arrayOf(queue.substring(0, pos)) //压入分隔的首段规则到数组
elementsType = queue.substring(pos, pos + step) //设置组合类型
pos += step //跳过分隔符 pos += step //跳过分隔符
elementsType = queue.substring(pos - step, pos) //设置组合类型
while (consumeToAny { matchesAny(* split) }) { //循环切分规则压入数组 while (consumeToAny(* split)) { //循环切分规则压入数组
rule += queue.substring(start, pos) rule += queue.substring(start, pos)
pos += step //跳过分隔符 pos += step //跳过分隔符
} }
rule+= queue.substring(start) //将剩余字段压入数组末尾
rule += queue.substring(pos) //将剩余字段压入数组末尾
return rule return rule
} }
@ -282,14 +288,16 @@ class RuleAnalyzer(data: String) {
var rule = arrayOf(queue.substring(0, pos)) //压入分隔的首段规则到数组 var rule = arrayOf(queue.substring(0, pos)) //压入分隔的首段规则到数组
elementsType = queue.substring(pos, pos + step) //设置组合类型
pos += step //跳过分隔符 pos += step //跳过分隔符
elementsType = queue.substring(pos - step, pos) //设置组合类型
while (pos < st && consumeToAny { matchesAny( * split ) }) { while (consumeToAny( * split ) && pos < st ) { //循环切分规则压入数组
rule += queue.substring(start, pos) //循环切分规则压入数组 rule += queue.substring(start, pos)
pos += step //跳过分隔符 pos += step //跳过分隔符
} }
rule rule
}else null }else null
pos = st //位置推移到筛选器处 pos = st //位置推移到筛选器处
@ -316,9 +324,7 @@ class RuleAnalyzer(data: String) {
if (!consumeTo(elementsType,false)) return rules + queue.substring(start) //此处consumeTo(...)开始位置不是规则的开始位置,start沿用上次设置 if (!consumeTo(elementsType,false)) return rules + queue.substring(start) //此处consumeTo(...)开始位置不是规则的开始位置,start沿用上次设置
end = pos val st = findToAny( '(','[' ) //查找筛选器
val st = if( consumeToAny(false){ matchesAny( '(','[' ) } )pos else -1 //查找筛选器
pos = end
if(st == -1) { if(st == -1) {
var rule = rules + queue.substring(start, pos) //压入本次分隔的首段规则到数组 var rule = rules + queue.substring(start, pos) //压入本次分隔的首段规则到数组
@ -327,14 +333,14 @@ class RuleAnalyzer(data: String) {
rule += queue.substring(start, pos) rule += queue.substring(start, pos)
pos += step //跳过分隔符 pos += step //跳过分隔符
} }
rule += queue.substring(start) //将剩余字段压入数组末尾 rule += queue.substring(pos) //将剩余字段压入数组末尾
return rule return rule
} }
val rule = if(st > pos ){//先匹配到st1pos,表明"&&","||"不在选择器中,将选择器前"&&","||"分隔的字段依次压入数组 val rule = if(st > pos ){//先匹配到st1pos,表明"&&","||"不在选择器中,将选择器前"&&","||"分隔的字段依次压入数组
var rule = rules + queue.substring(start, pos) //压入本次分隔的首段规则到数组 var rule = rules + queue.substring(start, pos) //压入本次分隔的首段规则到数组
pos += step //跳过分隔符 pos += step //跳过分隔符
while (pos < st && consumeTo(elementsType)) { //循环切分规则压入数组 while (consumeTo(elementsType) && pos < st) { //循环切分规则压入数组
rule += queue.substring(start, pos) rule += queue.substring(start, pos)
pos += step //跳过分隔符 pos += step //跳过分隔符
} }
@ -512,4 +518,4 @@ class RuleAnalyzer(data: String) {
val splitListDefault = arrayOf("-",".","!","@","@@") val splitListDefault = arrayOf("-",".","!","@","@@")
} }
} }

Loading…
Cancel
Save