Expressões regulares no PowerShell
LidoAula sobre expressões regulares no PowerShell, cobrindo operadores -match, -replace, a classe [regex] e o uso de grupos de captura, com exemplos práticos e exercícios.
Expressões regulares (regex) são uma ferramenta poderosa para busca, extração e substituição de padrões em texto. No PowerShell, você pode usar regex de várias formas: com os operadores -match e -replace, ou com a classe [regex] do .NET. Nesta aula, vamos explorar essas técnicas, entender como capturar grupos e aplicar em situações reais.
Dominar regex no PowerShell é essencial para automatizar tarefas de processamento de texto, logs, validação de entradas e manipulação de dados. Vamos começar com os operadores básicos e avançar para recursos mais sofisticados.
-match e $Matches
O operador -match testa se uma string corresponde a um padrão regex. Ele retorna $true ou $false e, quando verdadeiro, preenche a variável automática $Matches com o resultado da correspondência.
É importante notar que -match é case-insensitive por padrão, mas você pode usar -cmatch para tornar sensível a maiúsculas/minúsculas. O padrão regex é aplicado à string à esquerda do operador, e o padrão é a string à direita.
$texto = "O número de pedido é 12345"
if ($texto -match '\d+') {
Write-Host "Encontrado: $($Matches[0])"
} else {
Write-Host "Nenhum número encontrado"
}
# Saída: Encontrado: 12345O índice 0 de $Matches contém a correspondência completa. Se houver grupos de captura, eles ficam nos índices 1, 2, etc. Veremos mais sobre grupos adiante.
Uma dica: lembre-se de escapar caracteres especiais com \ se quiser corresponder literalmente, como ponto (\.) ou barra invertida.
-replace com regex
O operador -replace substitui todas as ocorrências de um padrão por uma string de substituição. Ele também usa regex por padrão, mas você pode usar -creplace para diferenciar maiúsculas/minúsculas.
Na string de substituição, você pode referenciar grupos capturados usando $1, $2, etc., ou ${nome} se nomeou os grupos. Isso permite reordenar ou transformar partes do texto.
$frase = "A data é 25/12/2024"
$nova = $frase -replace '(\d{2})/(\d{2})/(\d{4})', '$3-$2-$1'
Write-Host $nova
# Saída: A data é 2024-12-25Se você precisar substituir apenas a primeira ocorrência, não há um operador direto, mas pode usar [regex]::Replace com contagem ou um truque com -replace e substituição limitada. Para a maioria dos casos, -replace substitui todas as ocorrências, o que é suficiente.
Lembre-se de que -replace não modifica a variável original; ele retorna uma nova string. Para modificar in-place, atribua de volta: $var = $var -replace ....
[regex]
A classe [regex] do .NET oferece métodos estáticos e instâncias para operações regex mais avançadas. Você pode criar um objeto [regex] com um padrão e opções, e então usar métodos como Match, Matches, Replace e Split.
Isso é útil quando você precisa reutilizar o mesmo padrão várias vezes, aplicar opções como IgnoreCase ou Multiline, ou obter mais informações sobre as correspondências.
$regex = [regex]'(\d{3})-(\d{3})-(\d{4})'
$telefone = "Ligue para 555-123-4567 ou 555-987-6543"
$matches = $regex.Matches($telefone)
foreach ($m in $matches) {
Write-Host "Telefone: $($m.Value) - Código área: $($m.Groups[1].Value)"
}
# Saída:
# Telefone: 555-123-4567 - Código área: 555
# Telefone: 555-987-6543 - Código área: 555Outra vantagem é o método [regex]::Escape() que escapa todos os caracteres especiais de uma string para que sejam tratados literalmente. Por exemplo, se você está buscando um texto com pontos e parênteses, use Escape para evitar interpretação indevida.
$literal = [regex]::Escape("(versão 1.0)")
if ("Teste (versão 1.0) ok" -match $literal) {
Write-Host "Encontrado literal"
}Além disso, [regex] permite usar opções como [regex]::Options ou construtor com opções, por exemplo: [regex]::new(pattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase).
Grupos
Grupos de captura são partes da expressão entre parênteses. Eles permitem extrair subpartes da correspondência. No PowerShell, você acessa os grupos por índice (1, 2, ...) ou por nome se usar a sintaxe (?<nome>...).
Grupos são úteis para validar formatos e extrair informações específicas, como em logs ou dados estruturados.
$log = "2024-05-01 10:30:00 ERRO: Falha na conexão"
if ($log -match '(?\d{4}-\d{2}-\d{2}) (?\d{2}:\d{2}:\d{2}) (?\w+): (?.*)') {
Write-Host "Data: $($Matches['data'])"
Write-Host "Hora: $($Matches['hora'])"
Write-Host "Nível: $($Matches['nivel'])"
Write-Host "Mensagem: $($Matches['mensagem'])"
} Você também pode usar grupos para fazer substituições condicionais ou reordenar partes. No -replace, grupos nomeados são referenciados como ${nome}.
$nome = "Silva, João"
$nomeInvertido = $nome -replace '(?\w+), (?\w+)', '${nome} ${sobrenome}'
Write-Host $nomeInvertido
# Saída: João Silva Lembre-se de que grupos que não capturam (usando (?:...)) não são armazenados em $Matches, o que pode ser útil para agrupar sem poluir os resultados.
Boas práticas e observações
Ao trabalhar com regex no PowerShell, lembre-se de:
- Testar suas expressões em um ambiente controlado, como o console, antes de usá-las em scripts críticos.
- Usar aspas simples para padrões, evitando que o PowerShell expanda variáveis ou caracteres especiais.
- Comentar expressões complexas com
#dentro do padrão, se usarIgnorePatternWhitespace, mas lembre-se de que isso pode exigir opções. - Preferir
[regex]quando precisar de reutilização ou opções avançadas. - Escapar sempre que necessário com
[regex]::Escape()para entradas de usuário.
Exercícios
- Escreva uma expressão regular para validar um endereço de e-mail simples (formato algo@dominio.com). Use
-matchpara testar e exiba o domínio. - Use
-replacepara transformar uma string "João da Silva" em "SILVA, João" (sobrescreva o nome). - Dada a string "Erro 404: Página não encontrada", extraia o código do erro usando grupos nomeados.
- Use
[regex]::Replacepara substituir todas as ocorrências de múltiplos espaços por um único espaço, em uma string com espaços extras. - Escreva um script que use
[regex]para encontrar todas as datas no formato dd/mm/aaaa em uma string e exiba cada data no formato aaaa-mm-dd.
$email = "usuario@dominio.com"
if ($email -match '^[\w.-]+@([\w-]+)\.\w+$') {
Write-Host "Domínio: $($Matches[1])"
}$nome = "João da Silva"
$nomeInvertido = $nome -replace '^(\w+)\s+(.+)$', '$2, $1'
Write-Host $nomeInvertido.ToUpper()
# Ou mais simples: $nome -replace '^(\w+)\s+(.+)$', '$2, $1'$texto = "Erro 404: Página não encontrada"
if ($texto -match 'Erro (?\d+):') {
Write-Host "Código: $($Matches['codigo'])"
} $texto = "Este texto tem espaços extras."
$limpo = [regex]::Replace($texto, '\s+', ' ')
Write-Host $limpo$texto = "As datas são 25/12/2024 e 01/01/2025."
$regex = [regex]'(\d{2})/(\d{2})/(\d{4})'
foreach ($m in $regex.Matches($texto)) {
$dia = $m.Groups[1].Value
$mes = $m.Groups[2].Value
$ano = $m.Groups[3].Value
Write-Host "$ano-$mes-$dia"
}