How to divide String by regex? e.g. `"AAA{foo}BBB{...
# getting-started
k
How to divide String by regex? e.g.
"AAA{foo}BBB{bar}CCC"
to
["AAA", "{foo}", "BBB", "{bar}", "CCC"]
if regex is
\{.*?}
t
A normal split operation won't do becasue the separator is usually not included in the result. you could do something like this for your specific case:
Copy code
fun customSplit(input: String): List<String> {
    return "([^{]+)(\\{.*?})?".toRegex().findAll(input).flatMap { match ->
        sequence {
            yield(match.groupValues[1])
            match.groupValues[2].takeIf { it.isNotBlank() }?.let { yield(it) }
        }
    }.toList()
}
e
zero-width lookahead/lookbehind:
Copy code
"AAA{foo}BBB{bar}CCC".split("""(?=\{)|(?<=})""".toRegex())
(not all JS RegExp engines support lookbehind though)
t
good idea, didn't think of this. I don't know the case where this will be used but it is probaby sufficient, although it will just split before each
{
and after each
}
.
e
yeah, both our solutions have some edge cases on different inputs
(what should happen on
{{{foo}
? yours drops the leading
{
, mine separates them)
k
It seems difficult to support some edge case like
AAA{foo}BBB{bar}CCC}DDD{EEE
etc..
t
sure, mine isn't perfect at all, it was just my first idea. Both approaches require some regex-skills if you want to customize
👍 1
Here is a different approach that takes any regex
Copy code
fun customSplit(input: String, regex: Regex): List<String> {
    var nextSliceIndex = 0
    val result = regex.findAll(input).fold(mutableListOf<String>()) { result, match ->
        val range = match.range
        result += input.slice(nextSliceIndex until range.first)
        result += input.slice(range)
        nextSliceIndex = range.last + 1
        result
    }
    if (nextSliceIndex < input.length) {
        result += input.substring(nextSliceIndex)
    }
    return result
}
👀 1
s
@ephemient you can use capture groups to handle your edge case
k
I will try to use Tobias's approach! Thank you everyone!