☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

Mostrar mensagens com a etiqueta Regex. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Regex. Mostrar todas as mensagens

segunda-feira, 9 de janeiro de 2017

Regex sem Mistérios — A Linguagem Secreta que Todo Programador COBOL Padawan Precisa Conhecer

 

Bellacosa Mainframe e o regex sem misterios

☕ Um Café no Bellacosa Mainframe

Regex sem Mistérios — A Linguagem Secreta que Todo Programador COBOL Padawan Precisa Conhecer

Como encontrar, validar, limpar e transformar dados caóticos usando Expressões Regulares — com exemplos, curiosidades, armadilhas e analogias dignas da Frota Estelar

Existe um momento inevitável na carreira de qualquer profissional de tecnologia.

Você recebe um arquivo.

À primeira vista, parece apenas mais um CSV inofensivo vindo de algum sistema legado, planilha departamental, parceiro comercial, API moderna ou aplicação construída às pressas numa sexta-feira à tarde.

Então você abre o arquivo.

E encontra isto:

JOAO   DA SILVA
João da Silva
 joao da silva
JOAO DA SILVA     

Depois aparecem os telefones:

11999999999
(11) 99999-9999
+55 11 99999-9999
11-99999-9999
99999 9999

Logo abaixo, as datas:

17/07/2026
2026-07-17
17-07-26
20260717
Jul 17, 2026

E, como se a tripulação tivesse entrado em uma anomalia temporal, surgem e-mails sem domínio, endereços IP impossíveis, preços com ponto e vírgula trocados, espaços em excesso e descrições misturadas com informações entre parênteses.

Nesse instante, o programador percebe que o problema não é apenas “ler o arquivo”.

O problema é reconhecer padrões dentro do caos.

É aí que entra a Regex.

Regex é a abreviação de Regular Expression, ou Expressão Regular. Trata-se de uma pequena linguagem especializada em localizar, validar, extrair, substituir e reorganizar padrões dentro de textos.

Pode parecer estranha no começo.

Uma Regex típica se parece com isso:

^[\w.-]+@[\w.-]+\.\w{2,}$

Para quem está começando, isso parece uma mensagem interceptada de uma nave romulana.

Mas, quando desmontamos a expressão peça por peça, tudo começa a fazer sentido.

E esse é o objetivo desta missão: mostrar que Regex não é magia negra, não é privilégio de cientistas de dados e tampouco exige decorar centenas de símbolos.

Você precisa aprender a enxergar os componentes.

Assim como um programa COBOL é construído com IDENTIFICATION DIVISION, DATA DIVISION, PROCEDURE DIVISION, campos PIC, condições, PERFORM e IF, uma Regex também é formada por pequenos blocos previsíveis.

Prepare o café, ajuste o uniforme da Frota e abra o terminal.

Nossa missão começa agora.


1. O que é uma Expressão Regular?

Uma Expressão Regular é uma descrição compacta de um padrão textual.

Imagine que você deseja encontrar todas as matrículas formadas por três letras seguidas de quatro números:

ABC1234
XPTO9876
ZOS2026

Você poderia procurar cada matrícula individualmente.

Mas isso seria impossível se existissem milhares delas.

Com Regex, você descreve o formato:

[A-Z]{3}\d{4}

Essa expressão significa:

[A-Z]  → uma letra maiúscula
{3}    → repetida exatamente três vezes
\d     → um dígito
{4}    → repetido exatamente quatro vezes

Portanto:

[A-Z]{3}\d{4}

significa:

encontre três letras maiúsculas seguidas de quatro números.

A Regex não precisa saber quais letras ou números aparecerão. Ela sabe apenas qual estrutura deve procurar.

Isso muda completamente a maneira de lidar com textos.


2. Regex é como uma cláusula PIC do COBOL

Para um programador COBOL, existe uma comparação especialmente útil.

Considere:

01 WS-CODIGO PIC X(3)9(4).

Esse campo espera:

  • três caracteres alfanuméricos;

  • quatro dígitos.

Em Regex, um padrão semelhante poderia ser:

^[A-Z]{3}\d{4}$

As duas construções descrevem um formato esperado.

A diferença é que a cláusula PIC define como o dado será armazenado em um campo COBOL, enquanto a Regex procura ou valida padrões em textos.

Podemos imaginar que a Regex é uma espécie de PIC móvel.

Ela percorre uma linha, um arquivo, uma página, um log ou uma coluna inteira procurando ocorrências compatíveis.

Essa analogia é poderosa porque retira a Regex do território do mistério.

Você já conhece a ideia.

Apenas muda a sintaxe.


3. Onde Regex aparece?

Muitos programadores COBOL acreditam que Regex pertence apenas ao mundo de JavaScript ou Python.

Nada poderia estar mais distante da realidade moderna.

Regex aparece em:

  • editores de texto;

  • ferramentas de ETL;

  • scripts Python;

  • Bash;

  • PowerShell;

  • Java;

  • JavaScript;

  • C#;

  • bancos de dados;

  • ferramentas de Data Analytics;

  • pipelines de DevOps;

  • Jenkins;

  • Git;

  • VS Code;

  • Notepad++;

  • Zowe;

  • Unix System Services;

  • análise de logs;

  • observabilidade;

  • segurança;

  • parsing de arquivos;

  • validação de APIs;

  • transformação de CSV;

  • tratamento de JSON e XML.

No universo IBM Z, talvez você não execute Regex diretamente em um programa COBOL tradicional, mas certamente poderá encontrá-la em scripts auxiliares, automações, pipelines, arquivos YAML, utilitários Linux, integrações REST e processos de modernização.

O mainframe não vive isolado.

Ele conversa com o restante da galáxia.

E Regex é um dos idiomas usados nessas comunicações.


4. Os símbolos fundamentais da Regex

Antes de estudar os quinze padrões essenciais, precisamos conhecer as peças básicas.

O ponto: .

Em Regex, o ponto normalmente representa qualquer caractere.

a.c

Pode encontrar:

abc
a1c
a-c
a_c

O ponto não significa necessariamente um ponto literal.

Para procurar um ponto verdadeiro, usamos:

\.

Esse detalhe é extremamente importante.

A expressão:

\d+.\d+

aceita:

12.50
12,50
12X50

Porque o ponto significa qualquer caractere.

A versão mais correta seria:

\d+\.\d+

Agora, o separador precisa ser realmente um ponto.


O asterisco: *

Representa zero ou mais ocorrências.

AB*

Pode aceitar:

A
AB
ABB
ABBBBB

O B pode não aparecer ou aparecer várias vezes.


O sinal de mais: +

Representa uma ou mais ocorrências.

AB+

Aceita:

AB
ABB
ABBBBB

Mas não aceita apenas:

A

O ponto de interrogação: ?

Indica que o elemento anterior é opcional.

https?

Aceita:

http
https

O s pode existir ou não.


Os colchetes: []

Definem uma classe de caracteres.

[ABC]

Procura:

A
B
C

Já:

[A-Z]

representa qualquer letra maiúscula entre A e Z.

E:

[0-9]

representa qualquer dígito.


\d

Representa um dígito.

\d

É semelhante a:

[0-9]

\w

Normalmente representa letras, números e sublinhado.

\w

Pode encontrar:

A
z
5
_

O comportamento exato pode variar conforme o mecanismo Regex e o suporte a Unicode.


\s

Representa caracteres de espaço em branco.

Pode incluir:

  • espaço normal;

  • tabulação;

  • quebra de linha;

  • retorno de carro.


Circunflexo: ^

Indica o começo da string ou da linha.

^ABC

Encontra:

ABC123

Mas não encontra:

000ABC123

Cifrão: $

Indica o final da string ou da linha.

XYZ$

Encontra:

123XYZ

Mas não:

XYZ123

Quando usamos:

^\d+$

estamos dizendo:

do começo ao fim, aceite somente dígitos.


Chaves: {}

Controlam quantidades.

\d{4}

Exatamente quatro dígitos.

\d{2,4}

Entre dois e quatro dígitos.

\d{2,}

Dois ou mais dígitos.


Parênteses: ()

Criam grupos.

(ABC)+

Pode encontrar:

ABC
ABCABC
ABCABCABC

Os grupos também podem capturar partes específicas do texto.


Barra vertical: |

Significa “ou”.

COBOL|PL/I|REXX

Encontra qualquer uma das três palavras.


5. Padrão 1 — Endereço de e-mail

Uma expressão prática para e-mails simples é:

^[\w.-]+@[\w.-]+\.[A-Za-z]{2,}$

Vamos desmontar:

^

Começo da string.

[\w.-]+

Uma ou mais letras, números, sublinhados, pontos ou hífens.

@

O caractere arroba obrigatório.

[\w.-]+

O domínio.

\.

Um ponto literal.

[A-Za-z]{2,}

Uma extensão com pelo menos duas letras.

$

Fim da string.

Aceita:

usuario@gmail.com
vagner.bellacosa@empresa.com.br
programador-cobol@mainframe.org

Rejeita:

usuario@
@empresa.com
usuario.com
usuario@empresa

Porém existe uma observação importante.

E-mails reais podem seguir regras muito complexas. O padrão oficial permite formatos que quase nunca vemos no dia a dia.

Portanto, uma Regex simples é excelente para detectar erros comuns, mas não deve ser considerada uma implementação completa de todas as regras possíveis de e-mail.

Uma dica prática: em sistemas reais, muitas vezes o melhor teste de e-mail é enviar uma mensagem de confirmação.

A Regex valida o formato.

O envio confirma a existência operacional.


6. Padrão 2 — Número de telefone

Telefone é um dos maiores desafios de validação.

Considere:

+55 11 99999-9999
(11) 99999-9999
11 99999 9999
11999999999
+1 (555) 123-4567

Não existe uma única Regex perfeita para todos os países.

Uma expressão prática para formatos brasileiros poderia ser:

^(?:\+55\s?)?(?:\(?\d{2}\)?\s?)?\d{4,5}[-\s]?\d{4}$

Ela permite:

  • código do Brasil opcional;

  • DDD opcional;

  • parênteses opcionais;

  • espaço ou hífen opcional;

  • telefone com oito ou nove dígitos locais.

Mesmo assim, formato válido não significa número existente.

Uma Regex pode aceitar:

(00) 00000-0000

Embora isso não represente um telefone real utilizável.

Em aplicações internacionais, o ideal é normalizar os dados e trabalhar com um padrão como E.164:

+5511999999999

Esse formato remove espaços, parênteses e hífens, preservando apenas o sinal de mais, o código do país e o número.


7. Padrão 3 — Data no formato DD/MM/AAAA

Uma expressão comum é:

\b(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[0-2])/\d{4}\b

Ela limita:

  • dia entre 01 e 31;

  • mês entre 01 e 12;

  • ano com quatro dígitos.

Aceita:

17/07/2026
01/01/2000
31/12/1999

Mas pode aceitar:

31/02/2026

Por quê?

Porque Regex reconhece formato, não necessariamente lógica de calendário.

Ela sabe que 31 está dentro de 01 a 31.

Ela sabe que 02 está dentro de 01 a 12.

Mas não sabe automaticamente que fevereiro não possui 31 dias.

Para validar datas reais, o procedimento recomendado é:

  1. usar Regex para verificar o formato;

  2. converter o texto para um tipo de data;

  3. deixar a linguagem ou banco de dados validar o calendário.

É o equivalente a uma primeira inspeção feita pelo sensor da nave, seguida por uma análise completa no computador de bordo.


8. Padrão 4 — Data ISO AAAA-MM-DD

\b\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])\b

Aceita:

2026-07-17
2025-12-31
2000-01-01

O formato ISO é excelente porque organiza as partes da maior para a menor:

ano-mês-dia

Isso traz vantagens para ordenação textual.

Considere:

2024-12-31
2025-01-01
2026-07-17

Mesmo como texto, a ordem cronológica é preservada.

Por isso, esse formato aparece em:

  • APIs;

  • bancos de dados;

  • logs;

  • arquivos CSV;

  • integrações;

  • sistemas distribuídos;

  • aplicações modernas.

Para um programador COBOL envolvido com APIs e modernização, o formato ISO deve se tornar um velho amigo.


9. Padrão 5 — Horário HH:MM

\b([01][0-9]|2[0-3]):[0-5][0-9]\b

Aceita:

00:00
09:30
18:45
23:59

Rejeita:

24:00
12:99
99:99

A primeira parte:

([01][0-9]|2[0-3])

aceita horas de 00 a 23.

A segunda:

[0-5][0-9]

aceita minutos de 00 a 59.

Essa expressão é muito útil para:

  • logs de processamento batch;

  • registros de ponto;

  • agendas;

  • monitoramento;

  • relatórios operacionais;

  • arquivos de auditoria.


10. Padrão 6 — URL

Uma Regex simples:

https?://[^\s]+

Significa:

http
seguido de um s opcional
seguido de ://
seguido de um ou mais caracteres que não sejam espaços

Aceita:

https://www.ibm.com
http://servidor.local/relatorio
https://exemplo.com/api/clientes?id=10

Essa expressão é útil para extração, mas não valida toda a estrutura de uma URL.

Também pode capturar pontuação colada no final:

Acesse https://exemplo.com.

Dependendo do mecanismo, o ponto final poderá entrar na captura.

Podemos refinar o padrão, mas existe uma lição importante:

quanto mais perfeita tentamos tornar uma Regex, mais complexa e difícil de manter ela pode ficar.

Regex deve resolver o problema necessário, não todos os problemas possíveis do universo.


11. Padrão 7 — Nome de domínio

Uma expressão prática:

\b(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,}\b

Pode encontrar:

ibm.com
empresa.com.br
portal.exemplo.org
mainframe.local

Esse tipo de extração aparece em:

  • análise de leads;

  • classificação de empresas;

  • segurança;

  • logs;

  • marketing;

  • inventário de URLs;

  • descoberta de integrações.

Por exemplo, a partir do e-mail:

usuario@empresa.com.br

podemos extrair:

empresa.com.br

E então agrupar contatos por organização.


12. Padrão 8 — Endereço IPv4

Uma expressão estrutural simples:

\b(?:\d{1,3}\.){3}\d{1,3}\b

Ela encontra:

192.168.0.1
10.0.0.25
172.16.1.100

Porém também pode aceitar:

999.999.999.999

Isso acontece porque cada bloco aceita de um a três dígitos, sem verificar o limite de 255.

Uma versão mais rigorosa é:

\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b

Essa expressão é mais precisa, mas também muito menos legível.

Aqui surge uma decisão de engenharia:

  • você precisa apenas extrair valores com aparência de IP?

  • ou precisa validar endereços IPv4 rigorosamente?

Para extração inicial de logs, a versão simples pode bastar.

Para segurança ou configuração de rede, a versão rigorosa ou uma biblioteca de IP é mais apropriada.


13. Padrão 9 — Valores monetários

Valores monetários são traiçoeiros porque cada país usa formatos diferentes.

Brasil:

R$ 1.299,99
R$ 25,00
1.000.000,50

Estados Unidos:

$1,299.99
$25.00
1,000,000.50

Uma expressão básica para valores brasileiros:

R\$\s?\d{1,3}(?:\.\d{3})*(?:,\d{2})?

Aceita:

R$ 25
R$ 1.299,99
R$ 10.000.000,50

Uma expressão básica para valores em dólares:

\$\s?\d{1,3}(?:,\d{3})*(?:\.\d{2})?

Nunca assuma o separador decimal sem conhecer a origem do dado.

Um erro de interpretação pode transformar:

1.234

em mil duzentos e trinta e quatro ou em um vírgula duzentos e trinta e quatro, dependendo da convenção utilizada.

Em sistemas financeiros, esse detalhe não é cosmético.

É crítico.


14. Padrão 10 — Percentuais

\b\d+(?:[.,]\d+)?%

Aceita:

18%
42,5%
98.75%

A parte:

(?:[.,]\d+)?

permite uma parte decimal opcional com ponto ou vírgula.

Mas novamente devemos perguntar:

  • o valor máximo é 100%?

  • valores acima de 100% são permitidos?

  • números negativos são válidos?

  • deve haver espaço antes do sinal de porcentagem?

Em relatórios de crescimento, isto pode ser válido:

250%

Em progresso de uma tarefa, talvez não.

A Regex deve refletir a regra do negócio, não apenas a aparência do dado.


15. Padrão 11 — Somente números

^\d+$

É uma das expressões mais úteis de todas.

Ela verifica se a string inteira possui apenas dígitos.

Aceita:

12345
000001
987654321

Rejeita:

123A
12-34
 123
123 

Pode ser utilizada para validar:

  • matrícula;

  • código de cliente;

  • CPF sem máscara;

  • número de lote;

  • quantidade;

  • identificador numérico.

Mas cuidado: um campo formado apenas por dígitos não é necessariamente um número matemático.

Um CPF, CEP ou código de cliente pode começar com zero.

Se convertermos:

001234

para número, podemos obter:

1234

e perder informação.

Isso também é familiar ao programador COBOL.

Nem todo PIC 9 representa um valor que deve participar de cálculos. Às vezes ele é apenas um identificador composto por caracteres numéricos.


16. Padrão 12 — Número decimal

^-?\d+(?:\.\d+)?$

Aceita:

10
10.5
-25
-25.75

A parte:

-?

permite um sinal negativo opcional.

A parte:

\d+

exige pelo menos um dígito.

E:

(?:\.\d+)?

permite uma parte decimal opcional.

Para vírgula decimal brasileira:

^-?\d+(?:,\d+)?$

Ou, para aceitar ambos:

^-?\d+(?:[.,]\d+)?$

Entretanto, aceitar os dois formatos pode gerar ambiguidades em dados com separadores de milhar.

A melhor estratégia costuma ser:

  1. identificar o padrão de origem;

  2. remover separadores de milhar;

  3. normalizar o separador decimal;

  4. converter para número.


17. Padrão 13 — Remover espaços extras

\s+

Substitua por um único espaço:

" "

Antes:

Analista       de      Sistemas

Depois:

Analista de Sistemas

Esse padrão é extremamente poderoso.

Mas ele também pode substituir:

  • tabs;

  • quebras de linha;

  • múltiplos espaços.

Portanto, se você estiver trabalhando com um texto multilinha, pode acabar transformando parágrafos inteiros em uma única linha.

Para espaços horizontais apenas, alguns mecanismos oferecem:

[ \t]+

Isso procura espaços e tabulações, mas não quebras de linha.

Sempre teste a substituição em uma cópia do arquivo.

A primeira diretriz da Frota Estelar de tratamento de dados deveria ser:

nunca execute uma transformação destrutiva sem possuir backup e uma amostra de validação.


18. Padrão 14 — Remover espaços do começo e do final

^\s+|\s+$

Significa:

espaços no começo
OU
espaços no final

Antes:

"     Power BI Dashboard      "

Depois:

"Power BI Dashboard"

Essa operação é chamada de trim.

Em linguagens modernas, normalmente existe uma função pronta para isso.

Mesmo assim, a Regex é útil quando estamos fazendo substituições em massa dentro de um editor, ferramenta ETL ou arquivo inteiro.


19. Padrão 15 — Texto dentro de parênteses

Para capturar o conteúdo entre parênteses:

\((.*?)\)

Considere:

Plano Corporativo (Premium)

A captura será:

Premium

Os parênteses literais precisam ser escapados:

\(
\)

O trecho:

.*

significa qualquer caractere, zero ou mais vezes.

O ponto de interrogação torna a busca não gulosa:

.*?

Isso significa que a Regex captura o mínimo necessário.

Sem o ?, em:

Produto (Azul) Tamanho (Grande)

uma expressão gulosa poderia capturar:

(Azul) Tamanho (Grande)

Com:

\((.*?)\)

ela pode capturar separadamente:

Azul
Grande

O conceito de busca gulosa é uma das curiosidades mais importantes da Regex.

Um quantificador guloso tenta consumir o máximo possível.

Um quantificador não guloso tenta consumir o mínimo necessário.


20. Regex encontra formato, não verdade

Esta é provavelmente a lição mais importante de todo o artigo.

Uma Regex pode reconhecer que:

usuario@empresa.com

tem aparência de e-mail.

Mas não sabe se a caixa postal existe.

Pode reconhecer:

31/02/2026

como uma data estruturada.

Mas não sabe se o dia existe no calendário.

Pode reconhecer:

999.999.999.999

como algo semelhante a IPv4, dependendo da expressão.

Mas não sabe automaticamente que os octetos são inválidos.

Pode reconhecer:

R$ 999999999999

como valor monetário.

Mas não sabe se o valor faz sentido para aquela transação.

Regex trabalha na camada sintática.

A lógica de negócio trabalha na camada semântica.

Em linguagem de Frota Estelar:

Regex é o scanner. A aplicação é o oficial científico que interpreta o resultado.


21. Passo a passo para construir uma Regex

Não comece tentando escrever a expressão inteira.

Siga um processo.

Passo 1 — Reúna exemplos válidos

Imagine códigos:

CLI-0001
CLI-1025
CLI-9999

Passo 2 — Reúna exemplos inválidos

CLI0001
cli-0001
CLI-001
CLI-12345

Passo 3 — Identifique partes fixas

CLI-

Passo 4 — Identifique partes variáveis

Quatro dígitos:

\d{4}

Passo 5 — Monte o padrão

CLI-\d{4}

Passo 6 — Ancore o começo e o final

^CLI-\d{4}$

Passo 7 — Teste casos extremos

CLI-0000
CLI-9999
CLI-12A4
XCLI-0001
CLI-0001-TESTE

Passo 8 — Documente

Explique o que a Regex faz.

Não deixe apenas:

^(?:\+55\s?)?(?:\(?\d{2}\)?\s?)?\d{4,5}[-\s]?\d{4}$

Adicione um comentário no código ou documentação.

Uma Regex não documentada pode se tornar um artefato klingon perdido dentro do sistema.

Todos têm medo de alterá-la.

Ninguém sabe exatamente o que ela faz.


22. Regex em Python — pequeno laboratório

import re

dados = [
    "usuario@gmail.com",
    "email-invalido",
    "programador@empresa.com.br"
]

padrao = re.compile(r"^[\w.-]+@[\w.-]+\.[A-Za-z]{2,}$")

for valor in dados:
    if padrao.fullmatch(valor):
        print(f"Válido: {valor}")
    else:
        print(f"Inválido: {valor}")

Resultado esperado:

Válido: usuario@gmail.com
Inválido: email-invalido
Válido: programador@empresa.com.br

Observe o prefixo r antes da string:

r"..."

Em Python, isso cria uma raw string, reduzindo conflitos entre as barras invertidas da linguagem e as barras utilizadas pela Regex.


23. Regex no PowerShell

No Windows, um Padawan pode experimentar:

$email = "usuario@empresa.com"

if ($email -match '^[\w.-]+@[\w.-]+\.[A-Za-z]{2,}$') {
    Write-Host "E-mail válido"
} else {
    Write-Host "E-mail inválido"
}

Para substituir espaços repetidos:

$texto = "Programador      COBOL      Padawan"
$limpo = $texto -replace '\s+', ' '

Write-Host $limpo

Resultado:

Programador COBOL Padawan

24. Regex no Linux e no USS

Com grep:

grep -E '^[0-9]+$' arquivo.txt

Isso procura linhas compostas apenas por números.

Para encontrar datas ISO:

grep -E '\b[0-9]{4}-[0-9]{2}-[0-9]{2}\b' aplicacao.log

Com sed, podemos reduzir espaços:

sed -E 's/[[:space:]]+/ /g' arquivo.txt

No Unix System Services do z/OS, esses recursos podem fazer parte de scripts de automação, preparação de dados, análise de logs e pipelines DevOps.


25. Armadilhas comuns

Esquecer de escapar o ponto

Errado:

\d+.\d+

Melhor:

\d+\.\d+

Usar Regex para tudo

Regex não é a melhor ferramenta para interpretar estruturas profundamente aninhadas.

Tentar processar JSON ou XML complexo inteiramente com Regex costuma produzir soluções frágeis.

Para JSON, use um parser JSON.

Para XML, use um parser XML.

Use Regex para tarefas localizadas, como identificar padrões simples antes ou depois do parsing.


Criar uma expressão impossível de manter

Uma Regex gigantesca pode funcionar, mas tornar a manutenção perigosa.

Às vezes é melhor dividir a validação em etapas:

  1. normalizar;

  2. verificar formato;

  3. converter;

  4. aplicar regra de negócio.


Não considerar Unicode e acentos

Padrões como:

[A-Za-z]

não incluem automaticamente:

á
é
ç
õ
ü

Dependendo da linguagem, você pode usar recursos Unicode, propriedades como \p{L} ou flags específicas.


Não testar casos negativos

Muitas pessoas testam apenas entradas válidas.

Uma boa bateria de testes deve conter:

  • entradas válidas;

  • entradas inválidas;

  • valores vazios;

  • espaços;

  • caracteres especiais;

  • limites máximos;

  • limites mínimos;

  • texto muito longo;

  • acentos;

  • valores nulos.


26. Dicas de sobrevivência para o Padawan

Primeira dica: não memorize Regex inteiras.

Memorize conceitos:

^     começo
$     final
\d    dígito
\w    caractere de palavra
\s    espaço
+     uma ou mais vezes
*     zero ou mais vezes
?     opcional
[]    classe
()    grupo
|     ou
{}    quantidade

Segunda dica: construa aos poucos.

Terceira dica: teste em uma amostra pequena.

Quarta dica: mantenha exemplos válidos e inválidos.

Quinta dica: dê nome ao padrão no código.

Em vez de:

if re.match(r"^[\w.-]+@[\w.-]+\.[A-Za-z]{2,}$", texto):

prefira:

PADRAO_EMAIL_SIMPLES = r"^[\w.-]+@[\w.-]+\.[A-Za-z]{2,}$"

if re.match(PADRAO_EMAIL_SIMPLES, texto):

Sexta dica: documente limitações.

Exemplo:

Valida apenas o formato geral do e-mail.
Não implementa integralmente todas as regras da RFC.

Sétima dica: não confie em Regex como única barreira de segurança.

Regex pode ajudar a validar entrada, mas segurança exige escaping, parametrização, autorização, limites de tamanho e tratamento adequado de dados.


27. Easter egg da Frota Estelar

Imagine que o computador da USS Enterprise recebeu o seguinte log:

STARDATE=47634.44 | SHIP=NCC-1701-D | STATUS=WARP_CORE_WARNING
STARDATE=47634.45 | SHIP=NCC-1701-D | STATUS=STABLE
STARDATE=47634.46 | SHIP=NCC-74656 | STATUS=TRANSWARP_DETECTED

Queremos extrair apenas os registros da Enterprise-D:

SHIP=NCC-1701-D

Queremos extrair todas as naves:

SHIP=NCC-\d+(?:-[A-Z])?

Isso poderia encontrar:

SHIP=NCC-1701-D
SHIP=NCC-74656

Queremos extrair todas as datas estelares:

STARDATE=\d+\.\d+

E agora o Easter egg:

procure no log uma nave cujo registro contenha:

NCC-1701

Ao encontrar esse padrão, o sistema poderia responder:

Tea, Earl Grey, hot.

Sim, Padawan: até uma Regex pode conter espírito de tripulação.


28. Curiosidades sobre Regex

Expressões regulares possuem raízes na matemática e na ciência da computação teórica.

O conceito está relacionado a linguagens formais e autômatos finitos.

Posteriormente, Regex tornou-se popular em ferramentas de processamento de texto, especialmente no ambiente Unix e em linguagens como Perl.

Perl teve enorme influência na sintaxe moderna das expressões regulares.

Por isso, muitos mecanismos são chamados de “compatíveis com Perl” ou PCRE, de Perl Compatible Regular Expressions.

Mas nem toda implementação é idêntica.

Uma expressão que funciona em Python pode precisar de ajustes em:

  • Java;

  • JavaScript;

  • PowerShell;

  • grep;

  • sed;

  • banco de dados;

  • editor de texto.

Alguns mecanismos suportam:

  • lookahead;

  • lookbehind;

  • grupos nomeados;

  • Unicode avançado;

  • modo multilinha;

  • modo case-insensitive;

  • quantificadores não gulosos.

Outros possuem limitações.

Sempre confirme qual mecanismo Regex está sendo utilizado.


29. Regex e qualidade de dados

Regex não serve apenas para encontrar texto.

Ela participa diretamente da qualidade dos dados.

Podemos usar Regex para:

  • detectar campos fora do padrão;

  • separar registros válidos e inválidos;

  • normalizar entradas;

  • extrair partes relevantes;

  • mascarar informações;

  • remover ruído;

  • identificar anomalias;

  • construir regras de qualidade;

  • preparar dados para análise.

Imagine uma coluna com CPFs:

123.456.789-00
12345678900
123 456 789 00
CPF: 123.456.789-00

Primeiro, poderíamos remover tudo que não seja dígito:

\D

Substituindo por vazio.

Resultado:

12345678900
12345678900
12345678900
12345678900

Depois, validamos se existem onze dígitos:

^\d{11}$

Isso ainda não valida os dígitos verificadores do CPF.

Essa validação exige algoritmo específico.

Mais uma vez:

  • Regex normaliza e verifica a forma;

  • a lógica de negócio verifica o significado.


30. Um plano de aprendizado em sete missões

Missão 1 — Aprender os metacaracteres

Pratique:

.
*
+
?
^
$
[]
()
{}
|

Missão 2 — Aprender as classes

\d
\w
\s
\D
\W
\S

Missão 3 — Validar campos simples

Crie expressões para:

  • matrícula;

  • CEP;

  • data;

  • horário;

  • código de produto.

Missão 4 — Extrair informações

Use Regex para extrair:

  • e-mails;

  • URLs;

  • IPs;

  • números;

  • textos entre parênteses.

Missão 5 — Fazer substituições

Experimente:

  • reduzir espaços;

  • remover caracteres;

  • reorganizar datas;

  • limpar máscaras.

Missão 6 — Integrar com uma linguagem

Escolha:

  • Python;

  • PowerShell;

  • JavaScript;

  • Java;

  • REXX com apoio de ferramentas externas;

  • Bash no USS.

Missão 7 — Aplicar em um problema real

Pegue uma cópia de um arquivo bagunçado e execute um pequeno processo:

entrada
→ identificação
→ normalização
→ validação
→ rejeição
→ saída limpa

Esse fluxo transforma conhecimento em habilidade.


Conclusão — Regex não é magia; é reconhecimento de padrões

Quando olhamos pela primeira vez para:

^(?:\+55\s?)?(?:\(?\d{2}\)?\s?)?\d{4,5}[-\s]?\d{4}$

é natural sentir que estamos diante de uma linguagem extraterrestre.

Mas não estamos.

A expressão é formada por pequenas decisões:

  • começo da linha;

  • código do país opcional;

  • espaço opcional;

  • DDD opcional;

  • parênteses opcionais;

  • quatro ou cinco dígitos;

  • separador opcional;

  • quatro dígitos finais;

  • fim da linha.

Cada símbolo possui função.

Cada grupo representa uma regra.

A Regex só parece complicada quando tentamos enxergá-la inteira de uma vez.

O segredo é desmontá-la.

É exatamente como analisar um programa COBOL antigo com vinte mil linhas.

Você não compreende tudo olhando o fonte inteiro.

Você identifica:

  • arquivos;

  • layouts;

  • campos;

  • parágrafos;

  • chamadas;

  • condições;

  • regras;

  • pontos de entrada;

  • saídas.

Regex segue o mesmo princípio.

Divida.

Nomeie.

Teste.

Documente.

Evolua.

Não tente decorar todas as expressões possíveis. Nem Spock faria isso.

Aprenda os componentes fundamentais e mantenha um pequeno arsenal de padrões úteis.

O verdadeiro poder não está em possuir uma lista com quinze Regex.

Está em compreender como adaptá-las.

Quando chegar o arquivo com quarenta mil telefones inconsistentes, datas em cinco formatos e clientes cadastrados por sistemas de épocas diferentes, você não verá mais caos.

Você verá padrões.

E quando o restante da equipe perguntar como você conseguiu limpar o arquivo em minutos, ajuste o comunicador, olhe para a tela verde do terminal e responda com serenidade:

“Não foi magia. Foi lógica aplicada ao texto.”

Missão cumprida, tripulante.

O arquivo está limpo.

Os dados foram validados.

A Enterprise pode voltar à velocidade de dobra.


sexta-feira, 1 de fevereiro de 2002

🌑 CID KAGENOU E A CAIXA-PRETA DOS AUTÔMATOS — QUANDO O COBOL DESCOBRIU QUE TAMBÉM ERA UMA MÁQUINA DE ESTADOS

 

Bellacosa Mainframe e a caixa preta do automatos

☕ Um Café no Bellacosa Mainframe

🌑 CID KAGENOU E A CAIXA-PRETA DOS AUTÔMATOS — QUANDO O COBOL DESCOBRIU QUE TAMBÉM ERA UMA MÁQUINA DE ESTADOS

Autômatos finitos, máquinas de estados, linguagens regulares, regex, engenharia reversa, CPU, COBOL, testes, protocolos, segurança — e o dia em que Shadow descobriu que não precisava abrir a caixa-preta para descobrir o segredo escondido dentro dela.



🎬 PRÓLOGO — HÁ ALGUMA COISA ESCONDIDA NESSA CAIXA

Imagine Cid Kagenou entrando em uma dungeon.

Nenhum monstro.

Nenhum artefato mágico.

Nenhuma princesa sequestrada.

Alpha olha desconfiada para o centro da sala.

Ali existe apenas uma pequena caixa preta.

Na frente dela:

  • um terminal de entrada;

  • uma pequena lâmpada;

  • um botão escrito RESET.

Beta examina o equipamento.

— Shadow-sama, devemos desmontá-lo?

Cid cruza os braços.

— Não.

Silêncio dramático.

Naturalmente, todos imaginam que Shadow descobriu algum segredo ancestral.

Na realidade, ele simplesmente não sabe como abrir a caixa.

Mas, como frequentemente acontece em The Eminence in Shadow, uma frase improvisada acaba contendo uma ideia surpreendentemente profunda:

Não precisamos conhecer o interior de uma máquina para estudar seu comportamento.

E é justamente assim que começa nossa excursão pela Teoria dos Autômatos.

Pegue seu café.

Aperte o cinto.

Nosso ônibus vai balançar um pouco.



🚌 CAPÍTULO 1 — O ÔNIBUS DE TURING CHEGA À DUNGEON

A inspiração desta viagem vem de A. K. Dewdney, autor de The Turing Omnibus, livro concebido como uma série de excursões por diferentes territórios da Ciência da Computação.

A metáfora é maravilhosa.

Em vez de imaginar Ciência da Computação como um gigantesco manual técnico, imagine um ônibus.

Em cada parada visitamos alguma região:

AUTÔMATOS
     ↓
LINGUAGENS FORMAIS
     ↓
ALGORITMOS
     ↓
LÓGICA
     ↓
COMPLEXIDADE
     ↓
COMPUTABILIDADE
     ↓
INTELIGÊNCIA ARTIFICIAL
     ↓
...

Na primeira excursão encontramos justamente uma criatura aparentemente humilde:

o autômato finito.

Não deixe o nome assustar.

Vamos desmontar o conceito — sem desmontar nossa caixa.



📦 CAPÍTULO 2 — SHADOW ENCONTRA UMA CAIXA-PRETA

Nossa máquina possui uma entrada capaz de receber dois sinais:

0
1

Também possui uma lâmpada.

Quando determinada sequência é fornecida, a lâmpada eventualmente acende.

Podemos representar a máquina assim:

             ┌──────────────────────┐
0 ou 1 ─────►│                      │
             │      CAIXA-PRETA     │────► 💡
RESET ──────►│                      │
             └──────────────────────┘

Não sabemos o que existe dentro.

Pode haver:

transistores
circuitos
flip-flops
microcontrolador
relés
magia negra
um COBOL de 1978

Para nossa análise, isso não importa.

Estamos interessados em:

ENTRADA → COMPORTAMENTO → SAÍDA

Essa é uma abstração extremamente importante na computação.

Um programa COBOL pode executar:

CALL 'PAGTO001'

Você não precisa necessariamente conhecer cada instrução existente em PAGTO001 para utilizar sua interface corretamente.

Da mesma maneira, quando consumimos uma API:

POST /pagamento

podemos trabalhar com o contrato da API sem conhecer toda sua implementação.

A primeira lição da dungeon é, portanto:

Implementação e comportamento são coisas diferentes.



🧪 CAPÍTULO 3 — ALPHA COMEÇA OS EXPERIMENTOS

Vamos alimentar nossa máquina.

Depois de pressionar RESET:

0

Nada.

1

Nada.

0

Nada.

1

💡

A lâmpada acendeu.

Descobrimos:

0101

parece ser uma sequência aceita.

Alpha repete imediatamente:

0101

Nada.

Beta começa a escrever um relatório de 847 páginas explicando que provavelmente se trata de um artefato demoníaco.

Até alguém lembrar:

RESET.

Pressionamos RESET.

Executamos novamente:

0101

💡

Funciona.

Isso revela uma informação gigantesca.

A máquina lembra alguma coisa do que aconteceu anteriormente.



🧠 CAPÍTULO 4 — O SEGREDO CHAMA-SE ESTADO

Se a saída dependesse somente do último símbolo recebido, bastaria analisar:

entrada atual

Mas nossa experiência demonstra que o comportamento depende também da história anterior.

Existe alguma espécie de memória.

Na teoria dos autômatos chamamos essa informação de:

ESTADO

Estado não significa necessariamente uma variável armazenada em RAM.

Uma definição muito melhor seria:

Estado é a informação relevante sobre o passado necessária para decidir o comportamento futuro.

Essa frase vale ouro.

Imagine uma porta eletrônica.

Ela poderia possuir:

LOCKED
UNLOCKED

Quando recebe:

CARD_VALID

pode fazer:

LOCKED → UNLOCKED

Quando alguém abre a porta:

UNLOCKED → LOCKED

Não precisamos registrar toda a biografia da pessoa:

acordou às 07:00
tomou café
pegou o carro
chegou ao escritório
tirou o cartão do bolso
...

Nada disso interessa à porta.

A informação relevante é:

LOCKED

ou:

UNLOCKED

O estado é, portanto, uma espécie de compressão do passado.


🌑 CAPÍTULO 5 — SHADOW GARDEN DESCOBRE A MÁQUINA DE ESTADOS

Imagine uma catraca.

Estados:

Q0 = LOCKED
Q1 = UNLOCKED

Entradas:

COIN
PUSH

Podemos definir:

LOCKED + COIN → UNLOCKED
LOCKED + PUSH → LOCKED

UNLOCKED + PUSH → LOCKED
UNLOCKED + COIN → UNLOCKED

Isso pode ser colocado numa tabela:

Estado atualEntradaNovo estado
LOCKEDCOINUNLOCKED
LOCKEDPUSHLOCKED
UNLOCKEDPUSHLOCKED
UNLOCKEDCOINUNLOCKED

Temos uma máquina de estados.

E provavelmente você já programou alguma sem saber.


🧙 CAPÍTULO 6 — A DEFINIÇÃO MATEMÁTICA

Um autômato finito determinístico costuma ser definido pela quíntupla:

M = (Q, Σ, δ, q0, F)

Calma.

Não invoque ainda o compilador COBOL.

Vamos traduzir.

Q — conjunto de estados

Por exemplo:

Q = {q0,q1,q2,q3,q4,q5}

Σ — alfabeto

São os símbolos aceitos como entrada.

No nosso exemplo:

Σ = {0,1}

δ — função de transição

A famosa letra grega delta determina:

estado atual + entrada → próximo estado

Formalmente:

δ : Q × Σ → Q

Por exemplo:

δ(q3,0)=q5
δ(q3,1)=q4

q0 — estado inicial

É onde começamos depois do RESET.

F — estados finais

São os estados considerados de aceitação.

Quando terminamos de processar a entrada em algum deles:

💡

A sequência foi aceita.


💾 CAPÍTULO 7 — DELTA DESCOBRE QUE DELTA NÃO É APENAS UMA PERSONAGEM

Imagine a surpresa da própria Delta ao descobrir que existe uma função matemática chamada δ.

Se estivermos em:

q3

e recebermos:

1

podemos ter:

δ(q3,1)=q4

Isso significa simplesmente:

ESTADO ATUAL = Q3
ENTRADA = 1
NOVO ESTADO = Q4

Não existe mistério.

Na prática, poderíamos implementar isso em COBOL.


💻 CAPÍTULO 8 — O AUTÔMATO ENTRA NO COBOL

Considere:

01 WS-STATE       PIC X(02).
01 WS-INPUT       PIC X.

MOVE 'Q0' TO WS-STATE.

EVALUATE TRUE

   WHEN WS-STATE = 'Q0'
        AND WS-INPUT = '0'
        MOVE 'Q1' TO WS-STATE

   WHEN WS-STATE = 'Q0'
        AND WS-INPUT = '1'
        MOVE 'Q0' TO WS-STATE

   WHEN WS-STATE = 'Q1'
        AND WS-INPUT = '0'
        MOVE 'Q1' TO WS-STATE

   WHEN WS-STATE = 'Q1'
        AND WS-INPUT = '1'
        MOVE 'Q2' TO WS-STATE

END-EVALUATE.

Parabéns.

Acabamos de implementar parte de um autômato finito.

Uma implementação mais organizada poderia separar:

READ-INPUT
PROCESS-TRANSITION
CHECK-FINAL-STATE

Observe como conceitos aparentemente matemáticos começam a aparecer naturalmente no COBOL.


🔄 CAPÍTULO 9 — O RESET É O INITIALIZE DA DUNGEON

O botão RESET possui uma importância enorme.

Ele coloca a máquina novamente em:

q0

Imagine testar:

0101

e depois:

0100101

sem RESET.

O segundo teste não começa realmente do zero.

A máquina pode estar carregando o estado produzido pelo primeiro.

Na prática estamos testando algo parecido com:

01010100101

Isso possui uma conexão direta com testes de software.

Um teste confiável deve começar de condições conhecidas.

Algo como:

GIVEN estado conhecido
WHEN evento acontece
THEN resultado esperado

Em COBOL isso poderia significar:

INITIALIZE WS-AREA
MOVE ZERO TO WS-COUNTER
MOVE '00' TO WS-STATUS

Estado residual é uma fonte clássica de bugs.


🔬 CAPÍTULO 10 — SHADOW COMEÇA A ENGENHARIA REVERSA

Executamos vários experimentos.

Descobrimos que a caixa aceita:

0101
0100101
0100100101
0100100100101

Vamos reorganizar:

01             01
01 001         01
01 001 001     01
01 001 001 001 01

Há claramente um padrão:

01 (001)* 01

O símbolo:

*

é chamado estrela de Kleene.

Significa:

zero ou mais repetições.

Portanto:

(001)*

pode produzir:

ε
001
001001
001001001
001001001001
...

ε representa a palavra vazia.

Consequentemente:

01(001)*01

produz:

0101
0100101
0100100101
0100100100101
...

Acabamos de entrar no território das linguagens regulares.


📜 CAPÍTULO 11 — REGEX NÃO NASCEU PARA VALIDAR E-MAIL

Quando alguém fala em expressão regular, muitos programadores imediatamente pensam:

^[0-9]{5}-[0-9]{3}$

CEP.

Ou alguma criatura monstruosa utilizada para validar endereço de e-mail.

Mas existe uma teoria matemática muito mais profunda por trás disso.

A relação fundamental é:

┌─────────────────────┐
│ EXPRESSÃO REGULAR   │
└──────────┬──────────┘
           │
           ⇅
┌─────────────────────┐
│ AUTÔMATO FINITO     │
└──────────┬──────────┘
           │
           ⇅
┌─────────────────────┐
│ LINGUAGEM REGULAR   │
└─────────────────────┘

Essas são diferentes maneiras de descrever a mesma classe fundamental de linguagens.

Uma regex pode ser transformada em um autômato.

Um autômato pode ser utilizado para reconhecer uma linguagem regular.

Essa relação aparece na implementação de scanners, parsers simples, ferramentas de busca e compiladores.


⚠️ CAPÍTULO 12 — CID PERCEBE O PROBLEMA DA INDUÇÃO

Agora surge uma questão maravilhosa.

Testamos:

0101
0100101
0100100101
0100100100101

Todas funcionaram.

Podemos afirmar que:

01(001)*01

é realmente a linguagem completa da máquina?

Não.

Talvez a máquina aceite apenas:

n <= 4

Talvez rejeite a quinta repetição.

Ou a número 847.

Ou talvez exista algum comportamento especial depois de 65.535 símbolos.

Experimentar alguns casos não demonstra automaticamente uma regra infinita.

Esse é um princípio extremamente importante também para testes.


🧪 CAPÍTULO 13 — “FUNCIONOU NO MEU TESTE”

O programador executa:

100 → OK
200 → OK
300 → OK
400 → OK

e declara:

— Funciona.

Shadow aparece atrás dele.

— Você testou 32767?

Silêncio.

— E 32768?

Mais silêncio.

— 99999999?

O programador começa a suar.

Testes demonstram comportamento para os casos efetivamente observados.

Não provam automaticamente comportamento universal.

É exatamente o problema encontrado na caixa-preta.


🕵️ CAPÍTULO 14 — MAS E SE SOUBERMOS QUANTOS ESTADOS EXISTEM?

Agora alguém nos fornece uma informação adicional:

A máquina possui seis estados.

Isso muda profundamente o problema.

Imagine:

q0
q1
q2
q3
q4
q5

Depois de transições suficientes, algum estado inevitavelmente precisará reaparecer.

Por quê?

Porque só existem seis possibilidades.

Se continuarmos andando:

q0 → q1 → q2 → q3 → q4 → q5 → ?

o próximo estado necessariamente será algum estado já existente.

Surge então um ciclo:

        ┌──────────────┐
        ↓              │
q2 → q3 → q4 → q5 ────┘

E ciclos explicam repetições.

Como:

(001)*

Aqui começamos a enxergar a intuição que posteriormente aparece em resultados como o Pumping Lemma.


🏰 CAPÍTULO 15 — EXISTEM MONSTROS QUE O AUTÔMATO NÃO CONSEGUE DERROTAR

Considere:

ab
aabb
aaabbb
aaaabbbb

A regra é:

aⁿbⁿ

Precisamos garantir:

quantidade de a = quantidade de b

Agora imagine:

aaaaaaaaaaaaaaaa....

Para saber quantos b deverão aparecer posteriormente, precisamos lembrar quantos a foram encontrados.

Mas nosso autômato possui memória finita.

Se existem apenas:

q0 q1 q2 q3 q4 q5

como representar:

1
2
3
4
...
1.000.000

quantidades diferentes?

Não consegue.

Encontramos uma fronteira computacional.


🪜 CAPÍTULO 16 — A ESCADA DAS MÁQUINAS

Quando precisamos de memória adicional, utilizamos modelos mais poderosos.

De forma simplificada:

AUTÔMATO FINITO
       ↓
AUTÔMATO COM PILHA
       ↓
MODELOS MAIS PODEROSOS
       ↓
MÁQUINA DE TURING

O autômato com pilha pode trabalhar com estruturas como:

((()))

Cada abertura:

(

pode empilhar alguma informação.

Cada fechamento:

)

remove algo da pilha.

Isso permite reconhecer estruturas que um simples autômato finito não consegue reconhecer.

E estamos nos aproximando da Hierarquia de Chomsky e da teoria das linguagens formais.

A pequena lâmpada começou a ficar perigosamente interessante.


🖥️ CAPÍTULO 17 — ESTÁVAMOS ESTUDANDO UMA CPU?

Existe uma bela provocação no texto original adaptado:

estivemos estudando o funcionamento de uma CPU simples.

Precisamos colocar uma pequena ressalva técnica.

Uma CPU moderna não é simplesmente aquele pequeno DFA.

Entretanto, componentes de hardware e circuitos sequenciais podem ser modelados por máquinas de estados.

Imagine:

FETCH
  ↓
DECODE
  ↓
EXECUTE
  ↓
MEMORY
  ↓
WRITEBACK
  ↓
FETCH

O processador possui estados internos.

Sinais e resultados influenciam as próximas transições.

Assim, a teoria dos autômatos possui ligação genuína com projeto de hardware.


🏧 CAPÍTULO 18 — VOCÊ ESTÁ CERCADO POR MÁQUINAS DE ESTADOS

Olhe ao redor.

Um elevador:

STOPPED
MOVING_UP
MOVING_DOWN
DOOR_OPEN
DOOR_CLOSING

Um caixa eletrônico:

IDLE
 ↓
CARD_INSERTED
 ↓
PIN_VALIDATED
 ↓
AUTHENTICATED
 ↓
TRANSACTION
 ↓
EJECT_CARD

Uma aplicação:

LOGGED_OUT
 ↓
AUTHENTICATING
 ↓
LOGGED_IN
 ↓
SESSION_EXPIRED

Um pedido:

CREATED
 ↓
PAID
 ↓
PROCESSING
 ↓
SHIPPED
 ↓
DELIVERED

Até muitos protocolos de rede podem ser entendidos como máquinas de estados.


💳 CAPÍTULO 19 — O AUTÔMATO ENTRA NO MAINFRAME

Agora imagine processamento de cartões.

Uma transação poderia atravessar:

RECEIVED
    ↓
VALIDATED
    ↓
AUTHORIZED
    ↓
CAPTURED
    ↓
SETTLED

Ou:

RECEIVED
    ↓
VALIDATED
    ↓
DECLINED

Isso poderia estar espalhado por:

COBOL
CICS
Db2
VSAM
IBM MQ
batch
APIs

Mas conceitualmente temos uma máquina de estados.

Um programa poderia fazer:

EVALUATE WS-STATUS

   WHEN 'RECEIVED'
        PERFORM 2000-VALIDATE

   WHEN 'VALIDATED'
        PERFORM 3000-AUTHORIZE

   WHEN 'AUTHORIZED'
        PERFORM 4000-CAPTURE

   WHEN 'CAPTURED'
        PERFORM 5000-SETTLEMENT

END-EVALUATE.

O programador COBOL está implementando teoria dos autômatos sem necessariamente perceber.


⚔️ CAPÍTULO 20 — A TRANSIÇÃO PROIBIDA

Aqui aparece uma aplicação extremamente útil para manutenção de sistemas legados.

A documentação diz:

CREATED → PAID → SHIPPED

Mas encontramos:

CREATED → SHIPPED

Pergunta:

essa transição é válida?

Talvez tenhamos encontrado o bug.

Em vez de olhar apenas para milhares de linhas COBOL, podemos tentar descobrir:

ESTADOS
EVENTOS
TRANSIÇÕES
ESTADOS FINAIS

Um programa de 12.000 linhas talvez possa ser resumido como:

14 estados
43 transições
11 eventos
5 estados finais

Isso é ouro para engenharia reversa.


🔥 CAPÍTULO 21 — WAR ROOM ÀS 03:17

03:17.

Naturalmente.

O telefone toca.

Produção caiu.

No log:

03:17:00 RECEIVED
03:17:01 VALIDATED
03:17:02 AUTHORIZED
03:17:03 CAPTURED
03:17:04 ERROR

O programador procura:

IF
EVALUATE
GO TO
PERFORM

O DBA examina Db2.

O especialista CICS olha dumps.

O pessoal de infraestrutura examina CPU.

Shadow permanece no fundo da sala.

Até fazer uma pergunta:

CAPTURED → ERROR é uma transição permitida?

Silêncio.

Talvez o problema não esteja em uma instrução individual.

Talvez exista uma transição de negócio impossível.

E aí está nosso easter egg das 03:17.


🛡️ CAPÍTULO 22 — O AUTÔMATO VIRA RED TEAM

Máquinas de estados também ajudam a pensar segurança.

Imagine:

DISCONNECTED
     ↓ LOGIN
AUTHENTICATING
     ↓ SUCCESS
AUTHENTICATED

Mas alguém descobre:

DISCONNECTED
     ↓ EVENTO-X
ADMIN

Isso é interessantíssimo.

O atacante encontrou uma transição que não deveria existir.

Problemas semelhantes aparecem em:

protocolos
autenticação
workflows
APIs
sistemas distribuídos
model-based testing
fuzzing
engenharia reversa

Uma excelente estratégia de segurança é perguntar:

Quais estados existem e quais transições deveriam ser impossíveis?


🤖 CAPÍTULO 23 — A CAIXA-PRETA ENCONTRA A INTELIGÊNCIA ARTIFICIAL

Existe ainda uma conexão conceitual com IA.

Nosso experimento faz:

ENTRADAS
   ↓
OBSERVAÇÕES
   ↓
HIPÓTESE
   ↓
MODELO

Em aprendizado de máquina fazemos, em sentido muito amplo:

DADOS
   ↓
PADRÕES
   ↓
MODELO

Naturalmente um LLM moderno não deve ser confundido com o pequeno autômato da nossa dungeon.

Mas existe uma pergunta epistemológica comum:

Quanto podemos descobrir sobre um sistema observando somente seu comportamento externo?

Essa questão reaparece quando trabalhamos com sistemas proprietários, serviços remotos e modelos aos quais não temos acesso interno.

A caixa-preta continua conosco.


🔧 CAPÍTULO 24 — COMO USAR ESSA IDEIA NUM COBOL LEGADO

Agora uma dica extremamente prática.

Você recebe um programa desconhecido.

Não comece tentando entender todas as linhas simultaneamente.

PASSO 1 — descubra as entradas

Procure:

arquivos
COMMAREA
MQ
parâmetros
Db2
VSAM
SYSIN

PASSO 2 — identifique os estados

Procure campos como:

STATUS
STATE
SITUATION
TYPE
PHASE
STAGE
FLAG

PASSO 3 — encontre onde mudam

Pesquise:

MOVE 'XX' TO WS-STATUS

ou:

SET STATUS-APPROVED TO TRUE

PASSO 4 — construa uma tabela

Por exemplo:

EstadoEventoPróximo estado
RECEIVEDVALIDVALIDATED
RECEIVEDINVALIDREJECTED
VALIDATEDAPPROVEAUTHORIZED
VALIDATEDDENYDECLINED

PASSO 5 — desenhe o diagrama

Você pode descobrir uma arquitetura lógica que ninguém documentou.

PASSO 6 — procure transições impossíveis

Pergunte:

REJECTED → SETTLED ?
CANCELLED → AUTHORIZED ?
SHIPPED → CREATED ?

Esses caminhos merecem investigação.


🧠 CAPÍTULO 25 — O VERDADEIRO PODER DA ABSTRAÇÃO

Observe tudo que removemos da caixa:

voltagem
resistores
transistores
temperatura
fiação
material
clock
fabricante

E preservamos:

Q
Σ
δ
q0
F

Esse processo chama-se abstração.

Não estamos dizendo que detalhes físicos não existem.

Estamos dizendo:

para responder determinada pergunta, eles não são necessários.

Isso aparece em toda a computação.

Quando trabalhamos com COBOL:

arquivo lógico

podemos não precisar conhecer imediatamente a geometria física do disco.

Quando usamos Db2:

SELECT ...

não precisamos controlar manualmente cada bloco armazenado.

Quando utilizamos MQ:

PUT
GET

trabalhamos sobre uma abstração.

Camadas de abstração são uma das razões pelas quais conseguimos construir sistemas gigantescos.


☕ EPÍLOGO — SHADOW DESCOBRE O QUE SIGNIFICA COMPUTAR

Nossa excursão começou com:

0
1
RESET
💡

Parecia quase infantil.

Mas então descobrimos:

caixa-preta
     ↓
estado
     ↓
transição
     ↓
autômato
     ↓
linguagem
     ↓
expressão regular
     ↓
limites de memória
     ↓
linguagens formais
     ↓
computabilidade

Essa é a beleza da Ciência da Computação.

COBOL é importante.

Python é importante.

Java é importante.

Assembler é importante.

Mas existe um universo abaixo das linguagens:

LÓGICA
AUTÔMATOS
ALGORITMOS
LINGUAGENS FORMAIS
COMPLEXIDADE
COMPUTABILIDADE
INFORMAÇÃO

Um programador pode passar décadas escrevendo programas sem visitar profundamente esse território.

Mas quando começa a estudá-lo, algo muda.

Ele deixa de enxergar apenas:

IF
MOVE
PERFORM
EVALUATE

e começa a enxergar:

ESTADOS
TRANSIÇÕES
LINGUAGENS
MODELOS
INVARIANTES
LIMITES

E isso muda inclusive a maneira de investigar um COBOL legado.

Aquele monstro de 15.000 linhas talvez não seja simplesmente um amontoado de PERFORM, IF, copybooks e tabelas Db2.

Talvez escondido lá dentro exista algo muito mais elegante:

             ┌─────────────┐
             │  RECEIVED   │
             └──────┬──────┘
                    ↓
             ┌─────────────┐
             │  VALIDATED  │
             └──────┬──────┘
                ┌───┴───┐
                ↓       ↓
          AUTHORIZED  DECLINED
                ↓
            CAPTURED
                ↓
             SETTLED

Uma máquina de estados.

Uma descendente conceitual daquela pequena caixa-preta.

E talvez essa seja a grande lição deixada pela primeira parada do ônibus de Dewdney.

Não precisamos começar abrindo a máquina.

Primeiro podemos observar.

Experimentar.

Modelar.

Formular hipóteses.

Descobrir estados.

Mapear transições.

Procurar ciclos.

Encontrar exceções.

E somente depois descer às entranhas da implementação.

Alpha observa o diagrama.

Beta termina o volume 37 de As Crônicas Secretas da Máquina de Estados de Shadow-sama.

Delta continua indignada porque roubaram seu nome para uma função matemática.

Cid olha para a caixa-preta.

A lâmpada acende.

0100100101

Ele sorri.

— Exatamente como eu havia previsto.

Não havia previsto coisa nenhuma.

Mas desta vez estava correto.

☕ Um Café no Bellacosa Mainframe

Porque algumas vezes compreender 15.000 linhas de COBOL começa desenhando seis círculos e algumas flechas em um pedaço de papel.

Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...