Expressões regulares em Kotlin com exemplos: na prática
\n\nExpressões regulares (regex) são uma ferramenta poderosa para trabalhar com strings. Em Kotlin, elas são implementadas com base nas classes Java Pattern e Matcher, mas a linguagem adiciona suas próprias extensões convenientes e açúcar sintático. Neste artigo, vamos explorar como usar expressões regulares em Kotlin com exemplos reais: desde a busca simples até a substituição e divisão de strings.
Fundamentos da sintaxe: criação e compilação
\n\nEm Kotlin, uma expressão regular pode ser criada de duas maneiras: através da classe Regex ou usando uma string com o padrão. O primeiro método é preferível, pois oferece mais métodos.
// Método 1: através da classe Regex\nval regex = Regex("\\\\d+") // um ou mais dígitos\n\n// Método 2: através de string (não recomendado para expressões complexas)\nval pattern = "\\\\d+".toRegex()\n\nObserve a barra invertida dupla: \\\\d — isso é um escape para Java/Kotlin, a fim de obter o caractere \\d na string. Para simplificar, Kotlin suporta raw strings (aspas triplas """), onde o escape não é necessário:
val regex = Regex("""\\d+""") // raw string — barras invertidas não precisam ser duplicadas\n\nTambém é possível adicionar flags, por exemplo, RegexOption.IGNORE_CASE:
val regex = Regex("kotlin", RegexOption.IGNORE_CASE)\n\nBusca e verificação de correspondências
\n\nAs operações mais comuns são verificar se uma string contém uma substring que corresponde ao padrão e encontrar todas as correspondências.
\n\nVerificação de existência de correspondência: containsMatchIn
\n\nval text = "Meu número: 123-45-678"\nval digitRegex = Regex("""\\d+""")\n\nif (digitRegex.containsMatchIn(text)) {\n println("O texto contém dígitos!")\n}\n\nBusca da primeira correspondência: find
\n\nval result = digitRegex.find(text)\nprintln(result?.value) // Exibe: 123\n\nBusca de todas as correspondências: findAll
\n\nval allMatches = digitRegex.findAll(text)\nallMatches.forEach { match ->\n println("Encontrado: ${match.value}") // 123, 45, 678\n}\n\nO método findAll retorna uma sequência de objetos MatchResult. Cada um desses objetos contém não apenas a correspondência em si (.value), mas também sua posição na string (.range).
Trabalhando com grupos de captura
\n\nGrupos de captura são partes do padrão delimitadas por parênteses. Eles permitem extrair fragmentos específicos de dados. Por exemplo, vamos dividir um email em nome de usuário e domínio:
\n\nval email = "user@example.com"\nval emailRegex = Regex("""(.+)@(.+)""")\nval matchResult = emailRegex.find(email)\n\nif (matchResult != null) {\n val (username, domain) = matchResult.destructured\n println("Nome de usuário: $username") // user\n println("Domínio: $domain") // example.com\n}\n\nA construção destructured divide convenientemente os grupos em variáveis. Se houver mais grupos, pode-se acessar pelo índice:
val fullMatch = matchResult.value // user@example.com\nval group1 = matchResult.groupValues[1] // user\nval group2 = matchResult.groupValues[2] // example.com\n\nGrupos nomeados (Kotlin 1.7+)
\n\nA partir do Kotlin 1.7, é possível usar grupos nomeados:
\n\nval namedRegex = Regex("""(?<name>\\w+)@(?<domain>\\w+\\.\\w+)""")\nval match = namedRegex.find("contact@kotlin.org")\nif (match != null) {\n println(match.groups["name"]?.value) // contact\n println(match.groups["domain"]?.value) // kotlin.org\n}\n\nSubstituição de texto com replace
\n\nO método replace permite substituir todas as correspondências por uma nova string. No padrão de substituição, é possível referenciar grupos de captura com