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