I have the following expression written in a standard java-style with "if".
val punctuationChars = setOf('!', '?', '.')
if (text[index] in punctuationChars &&
text[index 1].isWhitespace() &&
text[index 2].isUpperCase()
){return index}
I want to rewrite it kotlin-style. I got something like this:
text.indexOfFirst { it in punctuationChars && (((it 1).isWhitespace()) && (it 2).isUpperCase()) }
And it absolutely does not work. But. If i use just like that:
text.indexOfFirst { it in punctuationChars }
It's working. So, how can i use multiple predicates in functions like this?
CodePudding user response:
I am pretty sure the first approach will work, you can even reduce number of brackets. Kotlin consumes logical expression, or a lambda of return type Boolean
. So you can use as many predicates as you want.
For your case you should simply use another method, filterIndexed
is what you want, it will give you a list of all indices matching your predicates. Just use the first one of them. You also should use safe get or null method, since you can run into IndexOutOfBounds
exception while accessing indices
return text.filterIndexed { index, it ->
it in punctuationChars
&& text.getOrNull(index 1)?.isWhitespace() == true
&& text.getOrNull(index 2)?.isUpperCase() == true
}.first()
CodePudding user response:
The direct equivalent to your Java-like code is the following:
fun indexOfEndOfSentenceAndStartOfNextSentence(text: String): Int =
(0 until text.length - 2).firstOrNull {
text[it] in ".!?" && text[it 1].isWhitespace() && text[it 2].isUpperCase()
} ?: -1
But using a regex may be better:
private val pattern = """[!?.]\s\p{Lu}""".toRegex()
fun indexOfEndOfSentenceAndStartOfNextSentence(text: String): Int =
pattern.find(text)?.let { it.range.first } ?: -1