Удобный для чтения подход регулярного выражения состоит в том, чтобы сопоставить любое количество символов от начала строки до 8-й цифры, а затем передать совпадение в блок и заменить второй раз цифрой:
val s = "123 456 789 0"
val regex = """^(?:\D*\d){8}""".toRegex()
println(s.replace(regex) { it.value.replace(Regex("""\d"""), "*") })
// => *** *** **9 0
См. Демоверсию Kotlin онлайн
Регулярное выражение ^(?:\D*\d){8}
соответствует
^
- начало строки (?:\D*\d){8}
-8 повторений: \D*
- 0 или более знаков, кроме цифр \d
- цифра.
ПростоК вашему сведению, вы можете добиться того же с помощью жестко закодированной версии с восемью группами захвата, s.replace("""^(\D*)\d(\D*)\d(\D*)\d(\D*)\d(\D*)\d(\D*)\d(\D*)\d(\D*)\d""".toRegex(), "$1*$2*$3*$4*$5*$6*$7*$8*")
, если у вас всегда есть 8 цифр во входной строке.