Search code examples
regexmaskinginput-mask

Find and replace regex for identification number input mask


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


Solution

  • 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.