1

I would like help to create an input masking using find and replace regexes for the following use case:

The user types 11 digits of his identification number and the output will be formatted with this pattern:

\d\d\d.\d\d\d.\d\d\d-\d\d

First attempt

Find: (\d{3})(\d{3})(\d{3})(\d{2})

Replace: $1.$2.$3-$4

This only works after the user types all the 11 digits. However, I want the dots and dashes to appear while the user types.

Second attempt

Find: (\d{1,3})(\d{1,3})(\d{1,3})(\d{1,2})

Replace: $1.$2.$3-$4

As soon as the user types the fourth digit, but the result ends up being like this \d.\d.\d-\d

Third attempt

Find: (\d{3})(\d{0,3})(\d{0,3})(\d{0,2})

Replace: $1.$2.$3-$4

As soon as the user types the third digit, but the result ends up being like this \d\d\d\..-

Code:

A brief description of the code:

fun transformation(input: String, findRegex: String, replaceRegex: String): String =
    input.replace(findRegex.toRegex(), replaceRegex)


fun main() {
    
    val input = "01121212"
    
    val findRegex = """(\d{3})(\d{3})(\d{3})(\d{2})"""

    val replaceRegex = """$1.$2.$3-$4"""
    
    val result = transformation(input, findRegex, replaceRegex)
    
    println(result)
}

https://pl.kotl.in/dPRrIMIVm

Full code can be found here: https://gitlab.com/pertence/masked-textinput

7
  • 1
    You forgot to use capturing groups that are referenced with the backreferences. Commented Jul 16, 2021 at 16:28
  • This answer stackoverflow.com/a/37681441/4770439 works and is the same as my first attempt, but I want I want the dots and dashes to appear while the user is typing. Commented Jul 16, 2021 at 16:42
  • 1
    Sorry, the regex works on plain text. When user is typing, there is some code that processes the input and applies the regex. What is your code? Also, see Input mask doesn't work when value is deleted Commented Jul 16, 2021 at 16:48
  • I put the code sample in the question. I know there are other questions about input masking with android compose, but I want to create a class that does not need a custom logic for each mask pattern. Commented Jul 17, 2021 at 11:30
  • 1
    I think you need this kind of solution. Commented Jul 17, 2021 at 14:12

1 Answer 1

1

You can use

fun transformation(input: String, findRegex: String, replaceRegex: String): String =
    input.replace("""\D+""".toRegex(), "").replace(findRegex.toRegex(), {
        it.groupValues[1].toString() + 
          (if (!it.groupValues[2].isNullOrEmpty()) ".${it.groupValues[2].toString()}"  else "") + 
          (if (!it.groupValues[3].isNullOrEmpty()) ".${it.groupValues[3].toString()}"  else "") + 
          (if (!it.groupValues[4].isNullOrEmpty()) "-${it.groupValues[4].toString()}"  else "")
    })
 
fun main(args: Array<String>) {
    val input = "0112121234" // 011.212.123-4
    // val input = "011" //  011
    // val input = "01121212" // 011.212.12
    // val input = "011212" // 011.212
    // val input = "01121" //  011.21
    // val input = "0112" //  011.2
    val findRegex = """^(\d{3})(\d{1,3})?(\d{1,3})?(\d{1,2})?$"""
    val replaceRegex = """$1.$2.$3-$4"""
    val result = transformation(input, findRegex, replaceRegex)
    println(result)
}

See the online Kotlin demo.

NOTES:

  • .replace("""\D+""".toRegex(), "") - removes all non-digits
  • .replace(findRegex.toRegex(), { it.groupValues[1].toString() + (if (!it.groupValues[2].isNullOrEmpty()) ".${it.groupValues[2].toString()}" else "") + (if (!it.groupValues[3].isNullOrEmpty()) ".${it.groupValues[3].toString()}" else "") + (if (!it.groupValues[4].isNullOrEmpty()) "-${it.groupValues[4].toString()}" else "") }) - matches a pattern and replaces the match with different replacements depending on whether a group matched or not.

The regex is

^(\d{3})(\d{1,3})?(\d{1,3})?(\d{1,2})?$

See the regex demo. Details:

  • ^ - start of string
  • (\d{3}) - Group 1: three digits
  • (\d{1,3})? - an optional Group 2 that matches one, two or three digits
  • (\d{1,3})? - an optional Group 3 that matches one, two or three digits
  • (\d{1,2})? - an optional Group 4 that matches one or two digits
  • $ - end of string.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.