При использовании regex.find(input,pos)
можно ли заставить kotlin рассматривать pos
как начало строки?
т.е.:
val s = "foo(2)"
/*let's say I already extracted "foo"
and now want to extract tokens '(', '2' and ')'
*/
val r1a = "\\(".toRegex()
val r1b = "\\)".toRegex()
println(r1a.find(s,3)?.let{"found '${it.value}'"} ?: "Nothing found")
println(r1b.find(s,3)?.let{"found '${it.value}'"} ?: "Nothing found")
println()
//this finds both
//but I only want to find '(' because it's at the beginning of the remaining string
val r2a = "^\\(".toRegex()
val r2b = "^\\)".toRegex()
println(r2a.find(s,3)?.let{"found '${it.value}'"} ?: "Nothing found")
println(r2b.find(s,3)?.let{"found '${it.value}'"} ?: "Nothing found")
println()
//this finds neither.
//I want the following behaviour:
val ss = s.substring(3)
println(r2a.find(ss,0)?.let{"found '${it.value}'"} ?: "Nothing found")
println(r2b.find(ss,0)?.let{"found '${it.value}'"} ?: "Nothing found")
println()
/*which finds '(' but not ')',
but without having to explicitly split the string
*/
( ideone version )
Есть ли способ сделать это?
РЕДАКТИРОВАТЬ
Я НЕ хочу сопоставить "foo (2) ".
Я хочу, чтобы можно было подать эту строку в список соответствий, которые будут соответствовать сначала foo
, затем (
, затем 2
, затем )
.
fun tokenizeLine(line:String){
var pos = 0
while(pos < line.length){
val result = nextToken(line,pos)
pos += result.consumed
result.token?.let { tokens.add(it) }
}
tokens.add(Token.EOL)
}
, где каждый сопоставитель возвращает один из
sealed class TokenizerResult(val consumed : Int, val token:Token?){
class Something(consumed:Int, token:Token):TokenizerResult(consumed,token)
class Skip(consumed:Int=0):TokenizerResult(consumed,null)
object Nothing:TokenizerResult(0,null)
}
и fun nextToken(input:String, pos:Int) : TokenizerResult
просматривает список сопоставителей, пока не закончится совпадение, чтобы попытаться или , один из сопоставителей возвращает что-тоэто не TokenizerResult.Nothing
.
val matchers = listOf( skipWhitespace, number, parensOpen, parensClose, identifier, ... )
for(m in matchers){
result = m(input,pos)
if(result != TNothing) break
}
if(result == TNothing){
...
}
return result
РЕДАКТИРОВАТЬ 2
Сопоставители обычно работают так:
class RawMatch(val regex:Regex) : Pattern{
override fun match(input: String, pos: Int, createToken: (value: String) -> Token): TokenizerResult {
return regex.find(input,pos)?.let { TSomething(it.value.length,createToken(it.value)) } ?: TNothing
}
}