Thought
Thought

Reputation: 5846

Picking first X digits in string and replace each digit with Character

I'm trying to replace all digits in a string with an *.

Right now i have this

val regex = "^[\\d+].{8}"
val pattern = Pattern.compile(regex)
code = code.replace(pattern.toRegex(), "*** *** *")

It kinda works, but i want to have * instead of "*** *** *" so the idea is to replace single digits instead of a block.

example string:

123 456 789 0

Upvotes: 1

Views: 2589

Answers (2)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626758

A readable regex approach is to match any amount of chars from the start of the string up to the 8th digit and then pass the match to a block and replace the second time with a digit pattern:

val s = "123 456 789 0"
val regex = """^(?:\D*\d){8}""".toRegex()
println(s.replace(regex) { it.value.replace(Regex("""\d"""), "*") })
// => *** *** **9 0

See the Kotlin demo online

The ^(?:\D*\d){8} regex matches

  • ^ - string start
  • (?:\D*\d){8} - 8 repetitions of:
    • \D* - 0 or more chars other than digits
    • \d - a digit.

Just FYI, you may achieve the same with a hardcoded version with eight capturing groups, 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*") if you always have 8 digits in the input string.

Upvotes: 2

Kevin Coppock
Kevin Coppock

Reputation: 134664

Rather than a regex, you probably just want to iterate n number of times until you've replaced the desired number of characters. Using a functional approach you could do something like:

fun String.redact(numDigits:Int = 8): String {
    val charArray = toCharArray()

    charArray.withIndex()
        .filter { (_, char) -> Character.isDigit(char) }
        .take(numDigits)
        .forEach { (index, _) -> charArray[index] = '*' }

    return String(charArray)
}

Then:

println("123 456 789 0".redact()) // *** *** **9 0

Upvotes: 0

Related Questions