Douglas Mesquita | 02/09/2016
Neste post irei escrever e exemplificar o uso de expressões regulares em possíveis situações bem como a sua utilização dentro do R. Para isso escolhi apresentar o pacote stringr além de algumas funções básicas contidas na base do R (base). Para conhecer a potencialidade das funções do pacote stringr e do base é necessário um bom conhecimento a respeito de expressões regulares.
Expressões regulares - RegEx
Expressão regular ou RegEx do inglês ‘Regular Expression’ é uma poderosa ferramenta para manipulação de strings. Esta ferramenta visa a identificação de padrões textuais ou padrões de caracteres que casam com um determinado padrão especificado.
Por exemplo, digamos que você tem uma base de dados com todas as palavras do dicionário e que o seu interesse é localizar as palavras terminadas em “ente”. Não é trivial procurar manualmente pois temos muitas palavras no dicionário. Uma pesquisa simples por “ente” pode resultar em palavras como “enteado” e “enterro”, que não são palavras do tipo desejado. Neste caso com o auxílio de expressões regulares, podemos procurar pelo seguinte padrão:
O sinal de dolar “$” indica que o padrão desejado “ente” está localizado no final da string. Desta forma apenas palavras terminadas em “ente” seriam encontradas. O metacaracter $ e muitos outros serão exemplificados ao longo deste texto.
As expressões regulares são utilizadas em diversos lugares (inclusive em um simples ctrl + f). Editores de texto localizam e substituem strings utilizando expressões regulares. IDE’s em geral (como o RStudio) realçam sintaxe e inclusive identificam possíveis problemas no código.
Além disso, quando temos uma base de dados com variáveis textuais, muitos problemas podem ocorrer. Neste caso, nós devemos conhecer ferramentas capazes de manipular este tipo de dado. Com isso economizamos muito tempo!!!
Uma outra aplicação interessante pode ser a crítica automática de entrada de dados. Dado um questionário, a resposta só é computada se estiver no padrão predefinido. Por exemplo, em uma entrada de CPF, espera-se que só hajam números. Caso o respondente ponha alguma letra, o sistema não computa a entrada.
A forma com que se trabalha com expressões regulares pode ser vista como uma linguagem. Assim sendo, não existe apenas uma só forma de lidar com elas pois as implementações variam de acordo com a ferramenta utilizada. Porém, uma implementação que se destaca chama-se “Perl”, sendo que muitas codificações derivam desta implementação. Para se ter ideia esta é a codificação utilizada em muitos pacotes/bibliotecas de “Python”, “C” e “R”.
Caracteres especiais (metacaracteres)
Nesta seção alguns dos metacaracteres mais importantes serão brevemente descritos e exemplificados. Os metacaracteres tem função muito importante nos códigos utilizando RegEx. Os metacaracteres definem padrões estruturais de uma string, por exemplo, se o padrão buscado encontra-se no inicio ou no final de uma string.
- “^”: Ao usar o metacaracter ^padrão espera-se encontrar strings que iniciam com o padrão especificado.
- “$”: Ao usar o metacaracter padrão$ espera-se encontrar strings que terminem com o padrão especificado.
“[padrão]”: A expressão [padrão] é chamada de classe de caracteres. Dentro de uma classe de caracteres os metacaracteres podem mudar de sentido. Fique atento!
^Bloco [a-p]$ = {Bloco a, Bloco b, …, Bloco p}
- Fora de uma classe de caracteres o símbolo “-” é um simples símbolo.
- Dentro da classe ele representa um intervalo. [0-9], [a-z], [A-Z]…
S[^a-z]G = {S.G, …, S4G, …, SAG}
- Fora de uma classe de caracteres o símbolo “^” expressa “procure no inicio de uma string”
- Sendo o primeiro caracter dentro da classe de caracteres representa negação.
- Não sendo o primeiro caracter dentro da classe de caracteres representa um simples símbolo
- [S.G] = {S.G, …, S4G, …, SaG, …, SAG, …}
- Fora de uma classe de caracteres o símbolo “.” representa um simples “.”.
- Dentro da classe ele representa um caracter qualquer. [0-9], [a-z], [A-Z]…
“|”: Ao usar o metacaracter “padrão_1|padrão_2” espera-se encontrar strings que contenham pelo menos um dos padrões especificados.
- “()”: Ao usar o metacaracter “(padrão)” o escopo do código é reduzido para o que está entre parênteses.
- “?i”: Ao usar o metacaracter “?i” ignora-se caso sensitivo, não importando se a letra ou palavra está em escrita em letras maiúsculas ou minúsculas.
- “?”: Ao usar o metacaracter “padrãox?” o código busca pelo padrão acrescido ou não de x.
- ‘*’: Ao usar o metacaracter padrão* o código busca pelo último digito (ou padrão entre parênteses) repetidos 0 ou mais vezes.
- ‘+’: Ao usar o metacaracter padrão+ o código busca pelo último digito (ou padrão entre parênteses) repetidos uma ou mais vezes.
Caracteres especiais (metasequencias)
Seu funcionamento depende da implementação
- ‘{n}’: Ao usar a metasequencia padrão{n} o código busca pelo último digito (ou padrão, entre parênteses) repetidos exatamente n vezes.
- ‘{n,}’: Ao usar a metasequencia padrão{n} o código busca pelo último digito (ou padrão, entre parênteses) repetidos n ou mais vezes.
- ‘{n,m}’: Ao usar a metasequencia padrão{n} o código busca pelo último digito (ou padrão, entre parênteses) repetidos entre n e m vezes.
- ‘\\w’: Ao usar a metasequencia padrão\\w o código busca pelo padrão concatenado com qualquer dígito [0-9], [a-z], [A-Z] excluíndo-se pontuações e outros símbolos.
- ‘\\W’: Ao usar a metasequencia padrão\\W o código busca pelo padrão concatenado com qualquer dígito diferente de [0-9], [a-z], [A-Z].
- ‘“\\<\\>”’: Ao usar a metasequencia \\<padrão\\> o código busca exatamente pelo padrão específicado.
- ‘“\\b”’: Ao usar a metasequencia \\bpadrão o código busca pelo primeiro digito (ou padrão, entre parênteses) apenas no inicio de uma palavra.
- ‘“\\B”’: Ao usar a metasequencia \\Bpadrão o código busca pelo primeiro digito (ou padrão, entre parênteses) apenas no meio de uma palavra.
- ‘“\\d”’: Ao usar a metasequencia \\d o código busca por números.
- ‘“\\s”’: Ao usar a metasequencia \\s o código busca por espaços.
Caracteres especiais (escape)
Algumas vezes os símbolos utilizados como metacaracteres podem fazer parte de uma string. Para localiza-los usam-se os períodos de escape. Exemplos:
- “\?” : por quê\? = {por quê?}
- ‘\”’ : \“debugar\” = {“debugar”}
Como pode ser visto, existem muitos metacaracteres e metasequencias. O uso conjunto dessas expressões pode fornecer ferramentas poderosas para tratamento de strings. Alguns exemplos de como combinar essas expressões:
(w{3}\\.[a-z]{3,10}\\.[a-z]{3})$
Resultados possíveis
www.voegol.com
www.kaggle.com
Resultados impossíveis
www.ufmg.br
www.g1.globo.com
\\<([0-9]{3}\\.[0-9]{3}\\.[0-9]{3}-[0-9]{2})\\>
Resultados possíveis
000.000.000-00
100.000.000-00
Resultados impossíveis
000 000 000-00
cpf: 000.000.000-00
O código pode ser tão complexo quanto se queira !!
stringr e base
Nesta seção as funcionalidades mais importantes do stringr e do base serão brevemente explicadas e exemplificadas.
str_c: Concatena strings (stringr).
strings_c1 <- letters[1:5]
strings_c2 <- LETTERS[1:5]
str_c(strings_c1, strings_c2, sep = " -> ", collapse = "; ")
## [1] "a -> A; b -> B; c -> C; d -> D; e -> E"
paste: Concatena strings (base).
paste(strings_c1, strings_c2, sep = " -> ", collapse = "; ")
## [1] "a -> A; b -> B; c -> C; d -> D; e -> E"
paste0: Concatena strings sem deixar espaços (base).
paste0(strings_c1, strings_c2, collapse = "; ")
## [1] "aA; bB; cC; dD; eE"
str_to_upper: Deixa a string completamente em letras maiúsculas (stringr).
strings_lower <- letters[1:5]
str_to_upper(string = strings_lower)
## [1] "A" "B" "C" "D" "E"
toupper: Deixa a string completamente em letras maiúsculas (base).
strings_lower <- letters[1:5]
toupper(x = strings_lower)
## [1] "A" "B" "C" "D" "E"
str_to_lower: Deixa a string completamente em letras minúsculas (stringr).
strings_upper <- LETTERS[1:5]
str_to_lower(string = strings_upper)
## [1] "a" "b" "c" "d" "e"
tolower: Deixa a string completamente em letras minúsculas (base).
strings_upper <- LETTERS[1:5]
tolower(strings_upper)
## [1] "a" "b" "c" "d" "e"
str_conv: Converte strings de acordo com a codificação desejada (stringr).
strings_conv <- c("Diferenças", "nas", "codificações")
strings_conv <- iconv(x = strings_conv, to = "Windows-1252")
strings_conv
## [1] "Diferen\xe7as" "nas" "codifica\xe7\xf5es"
str_conv(string = strings_conv, encoding = "Windows-1252")
## [1] "Diferenças" "nas" "codificações"
iconv: Converte strings de acordo com a codificação desejada (base).
iconv(x = strings_conv, from = "Windows-1252")
## [1] "Diferenças" "nas" "codificações"
str_count: Conta o número de vezes em que o padrão especificado foi encontrado na string (stringr).
strings_count <- c("#S4G", "#SQN", "#S4G #SQN")
str_count(string = strings_count, pattern = "#[0-9a-zA-Z]{3}")
## [1] 1 1 2
str_detect: Se o padrão desejado existe na string retorna TRUE caso contrário FALSE (stringr).
strings_detect <- c("Será que o código detecta o padrão #@!?")
str_detect(string = strings_detect, pattern = "#@!")
## [1] TRUE
str_dup: Replica as strings segundo uma contagem desejada (stringr).
strings_dup <- c("Gato", "Cachorro", "Galinha")
count <- c(2, 3, 1)
str_dup(string = strings_dup, times = count)
## [1] "GatoGato" "CachorroCachorroCachorro"
## [3] "Galinha"
str_extract: Retorna a primeira ocorrência do padrão especificado (stringr).
strings_extract <- c("Esse código", "pega a 1ª", "ocorrência de cada palavra")
str_extract(string = strings_extract, pattern = "[a-z]{4}")
## [1] "digo" "pega" "ocor"
str_extract(string = strings_extract, pattern = "[a-z]{4}$")
## [1] "digo" NA "avra"
str_extract(string = strings_extract, pattern = "[a-zA-Z]{4}")
## [1] "Esse" "pega" "ocor"
str_extract(string = strings_extract, pattern = "[0-9]")
## [1] NA "1" NA
str: Conta o número de letras em uma string incluindo espaços (stringr).
strings_length <- c("Quantas letras estão dentro desta string? Incluindo os espaços")
str_length(string = strings_length)
## [1] 62
str_locate: Retorna a posição de inicio e de fim da string desejada (stringr).
strings_locate <- c("Em que local está a string #?")
str_locate(string = strings_locate, pattern = c("Em", "#"))
## start end
## [1,] 1 2
## [2,] 28 28
str_match: Verifica se o padrão desejado existe na string de interesse e retorna tal padrão (stringr).
strings_match <- c("#FFFFFF")
str_match(string = strings_match, pattern = c("^#[A-Z]{6}$", "FFFFFF"))
## [,1]
## [1,] "#FFFFFF"
## [2,] "FFFFFF"
grep: Verifica se o padrão desejado existe na string de interesse e retorna tal padrão (base).
grep(x = strings_match, pattern = c("^#[A-Z]{6}$"), value = T) # Não vetorizada
## [1] "#FFFFFF"
str_order: Ordena as strings e retorna as posições (stringr).
strings_order <- c("#", "$", 0:9, LETTERS, letters)
str_order(x = strings_order, decreasing = F)
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 39 13 40 14 41 15 42 16 43 17 44
## [24] 18 45 19 46 20 47 21 48 22 49 23 50 24 51 25 52 26 53 27 54 28 55 29
## [47] 56 30 57 31 58 32 59 33 60 34 61 35 62 36 63 37 64 38
str_sort: Ordena as strings e retorna o vetor (stringr).
strings_sort <- c("#", "$", 0:9, LETTERS, letters)
str_sort(x = strings_order, decreasing = F)
## [1] "#" "$" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "A" "b" "B" "c"
## [18] "C" "d" "D" "e" "E" "f" "F" "g" "G" "h" "H" "i" "I" "j" "J" "k" "K"
## [35] "l" "L" "m" "M" "n" "N" "o" "O" "p" "P" "q" "Q" "r" "R" "s" "S" "t"
## [52] "T" "u" "U" "v" "V" "w" "W" "x" "X" "y" "Y" "z" "Z"
str_pad: Acrescenta um determinado padrão ao redor da string (stringr).
strings_pad <- c("Direita", "Esquerda", "Centro")
str_pad(string = strings_pad[1], side = "right", width = 30)
## [1] "Direita "
str_pad(string = strings_pad[2], side = "left", width = 30)
## [1] " Esquerda"
str_pad(string = strings_pad[3], side = "both", width = 30)
## [1] " Centro "
str_pad(string = strings_pad[3], side = "both", width = 30, pad = "*")
## [1] "************Centro************"
str_replace e str_replace_all: Substitui um determinado padrão por outro (stringr).
strings_replace <- c("Hey", "Jude", "don't", "make", "it", "bad", "take", "a", "sad", "song", "and", "make", "it", "better")
str_replace(string = strings_replace, pattern = "Jude", replacement = "Douglas")
## [1] "Hey" "Douglas" "don't" "make" "it" "bad" "take"
## [8] "a" "sad" "song" "and" "make" "it" "better"
str_replace(string = strings_replace, pattern = "[aeiou]", replacement = "_")
## [1] "H_y" "J_de" "d_n't" "m_ke" "_t" "b_d" "t_ke"
## [8] "_" "s_d" "s_ng" "_nd" "m_ke" "_t" "b_tter"
str_replace_all(string = strings_replace, pattern = "[aeiou]", replacement = "_")
## [1] "H_y" "J_d_" "d_n't" "m_k_" "_t" "b_d" "t_k_"
## [8] "_" "s_d" "s_ng" "_nd" "m_k_" "_t" "b_tt_r"
gsub: Substitui um determinado padrão por outro (base).
gsub(x = strings_replace, pattern = "[aeiou]", replacement = "_")
## [1] "H_y" "J_d_" "d_n't" "m_k_" "_t" "b_d" "t_k_"
## [8] "_" "s_d" "s_ng" "_nd" "m_k_" "_t" "b_tt_r"
str_split: Quebra a string de acordo com o padrão desejado. Retorna um vetor de strings e não mais uma string (stringr).
strings_split <- str_c(strings_replace, collapse = " ")
str_split(string = strings_split, pattern = " ")
## [[1]]
## [1] "Hey" "Jude" "don't" "make" "it" "bad" "take"
## [8] "a" "sad" "song" "and" "make" "it" "better"
str_sub: Retorna um pedaço da string (stringr).
strings_sub <- "Stats4Good"
str_sub(string = strings_sub, start = 1, end = 5)
## [1] "Stats"
str_sub(string = strings_sub, start = 7, end = 10)
## [1] "Good"
str_sub(string = strings_sub, start = c(1,7), end = c(5,10)) # Dados da PNAD com posição fixa.
## [1] "Stats" "Good"
substr: Retorna um pedaço da string (base)
strings_sub <- "Stats4Good"
str_sub(string = strings_sub, start = 1, end = 5)
## [1] "Stats"
str_sub(string = strings_sub, start = 7, end = 10)
## [1] "Good"
str_sub(string = strings_sub, start = c(1,7), end = c(5,10)) # Dados da PNAD com posição fixa.
## [1] "Stats" "Good"
str_subset: Retorna o grupo de strings que contém um determinado padrão (stringr).
strings_subset <- c("Estatística", "Ciências atuariais", "Matemática", "Ciências da computação")
str_subset(string = strings_subset, pattern = "a[a-z]{1,4}a[a-z]{1,4}a")
## [1] "Ciências atuariais"
str_subset(string = strings_subset, pattern = "^(E|e)")
## [1] "Estatística"
str_subset(string = strings_subset, pattern = "a$")
## [1] "Estatística" "Matemática"
str_trim: Retira espaçoes em branco desnecessários (stringr).
strings_trim <- c(" String cheia de espaços em branco nos extremos ")
str_trim(string = strings_trim)
## [1] "String cheia de espaços em branco nos extremos"
str_trunc: Trunca a string no número de caracteres desejado (stringr).
strings_trunc <- c("Mais firme do que prego em polenta")
str_trunc(string = strings_trunc, width = 20)
## [1] "Mais firme do que..."
str_trunc(string = strings_trunc, width = 20, side = "center")
## [1] "Mais firm... polenta"
str_wrap: Dado um texto a função realiza a quebra de linha de acordo com o número de letras desejado (por linha) (stringr).
strings_wrap <- c("In sem justo, commodo ut, suscipit at, pharetra vitae, orci. Duis sapien nunc, commodo et, interdum suscipit, sollicitudin et, dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam id dolor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Mauris dictum facilisis augue. Fusce tellus. Pellentesque arcu. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio a lectus. Sed elit dui, pellentesque a, faucibus vel, interdum nec, diam. Mauris dolor felis, sagittis at, luctus sed, aliquam non, tellus. Etiam ligula pede, sagittis quis, interdum ultricies, scelerisque eu, urna. Nullam at arcu a est sollicitudin euismod. Praesent dapibus. Duis bibendum, lectus ut viverra rhoncus, dolor nunc faucibus libero, eget facilisis enim ipsum id lacus. Nam sed tellus id magna elementum tincidunt.")
cat(str_wrap(string = strings_wrap, width = 100) , "\n")
## In sem justo, commodo ut, suscipit at, pharetra vitae, orci. Duis sapien nunc, commodo et,
## interdum suscipit, sollicitudin et, dolor. Pellentesque habitant morbi tristique senectus et netus
## et malesuada fames ac turpis egestas. Aliquam id dolor. Class aptent taciti sociosqu ad litora
## torquent per conubia nostra, per inceptos hymenaeos. Mauris dictum facilisis augue. Fusce tellus.
## Pellentesque arcu. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante,
## in pharetra metus odio a lectus. Sed elit dui, pellentesque a, faucibus vel, interdum nec, diam.
## Mauris dolor felis, sagittis at, luctus sed, aliquam non, tellus. Etiam ligula pede, sagittis
## quis, interdum ultricies, scelerisque eu, urna. Nullam at arcu a est sollicitudin euismod. Praesent
## dapibus. Duis bibendum, lectus ut viverra rhoncus, dolor nunc faucibus libero, eget facilisis enim
## ipsum id lacus. Nam sed tellus id magna elementum tincidunt.
Pergunta: por que usar o pacote stringr?
- Os nomes das funções são mais consistentes
- Os nomes dos parâmetros são mais consistentes
- O pacote é do Hadley Wickham. Então é garantia de qualidade!
- O pacote lida bem com NAs. Exemplo:
strings_na <- c(NA, "não", "é", "string")
paste(strings_na, collapse = " ")
## [1] "NA não é string"
str_c(strings_na, collapse = " ")
## [1] NA
Mãos à obra
Agora vamos por em prática o que aprendemos até aqui. Dois exemplos práticos serão abordados:
- Limpeza de um pequeno texto
- Criação de uma função que valida as entradas de informação
Limpando um texto
Para tentar usar os conhecimentos de expressões regulares considere o seguinte texto de Marcio Ricardo Medeiros Oliveira:
toda_Escolha___quE_você_FizEr_E_toda_DECisão_quE_você_toMar_ tErá_sEu_lado_boM_E_sEu_lado_ruiM.@.@_considErE-os__ coM_cuidado_E_toME_a_dEcisão.@UMa_rEsposta_ MEnos_quE_pErfEita_é_infinitaMEntE_MElhor_do_quE_não_fazEr_nada_.@ Tudo_quE_vocE_sE_dispõE_a_fazEr_EnvolvE_alguns_ riscos_E_dEsafios.@_Para_qualquEr_coisa_quE_você_EMprEEndEr_ ExistEM_ Muitas_razõEs_para_não_fazê-lo.@_PEsE_os_ riscos_E_os_bEnEfícios_E,_Então_assuMa_o_coMproMisso_dE_agir.@_DEcida_o_quE_você_ quEr_fazEr,coM_os_olhos_bEM_abErtos,E lEvE_isso_EM_frEntE_sEM_olhar_para_trás.@ ExistEM_Muitas_dirEçõEs_dEntrE_as_quais você_podE_EscolhEr.@_MEsMo_assiM,você_prEcisa_EscolhEr. @_Suas_possibilidadEs_são_ significativas_apEnas_quando_você_EscolhE alguMas_dElas__E_rEjEita_o_rEsto.@_TEntar_fazEr_tudo_ao_MEsMo_tEMpo_é_ tão_inútil_ quanto_não_tEntar_nada.@ DEfina-sE.@_Escolha_sEu_caMinho_E_coMEcE_ a_andar.@_DEcida_o_quE_quEr_fazEr_E_Mãos_à_obra.@
Problemas:
- O espaço está representado por “_”
- Excesso de espaços
- Letras maiúsculas onde não deve
- Letras minúsculas onde não deve
- Caracteres indesejados ("@")
Tratamento:
texto <- str_replace_all(string = texto, pattern = "_", replacement = " ")
texto <- str_replace_all(string = texto, pattern = "(\\s)+", replacement = " ")
texto <- str_to_lower(string = texto)
texto <- str_replace_all(string = texto, pattern = "@", replacement = "")
texto <- str_replace_all(string = texto, pattern = "\\s([!.?,])", replacement = "\\1")
texto <- str_replace_all(string = texto, pattern = "([!.?,])([\\w])", replacement = "\\1\\s\\2")
texto <- str_replace_all(string = texto, pattern = "([!.?,])+", replacement = "\\1")
texto <- gsub(x = texto, pattern = "([!.?]\\s)(\\w)|(^\\w)", replacement = "\\1\\U\\2\\U\\3", perl = T)
Toda escolha que você fizer e toda decisão que você tomar terá seu lado bom e seu lado ruim. Considere-os com cuidado e tome a decisão.suma resposta menos que perfeita é infinitamente melhor do que não fazer nada. Tudo que voce se dispõe a fazer envolve alguns riscos e desafios. Para qualquer coisa que você empreender existem muitas razões para não fazê-lo. Pese os riscos e os benefícios e, então assuma o compromisso de agir. Decida o que você quer fazer, com os olhos bem abertos, e leve isso em frente sem olhar para trás. Existem muitas direções dentre as quais você pode escolher. Mesmo assim, você precisa escolher. suas possibilidades são significativas apenas quando você escolhe algumas delas e rejeita o resto. Tentar fazer tudo ao mesmo tempo é tão inútil quanto não tentar nada. Defina-se. Escolha seu caminho e comece a andar. Decida o que quer fazer e mãos à obra.
Os comandos “\1”, “\2” usados no argumento replacement são chamados de backreference. São muito úteis quando o padrão que irá substituir faz parte do padrão procurado. “\1” refere-se ao primeiro escopo definido pelos parênteses “( )”.
Criando uma ferramenta de validação
Para demonstrar o possível uso de expressões regulares no contexto de ferramenta de validação, vamos explorar as possíveis entradas de um questionário de avaliação. O título do questionário será: Você considera o R uma ferramenta poderosa?
Para responder à este questionário o usuário deve criar um loggin e uma senha, pois, esse é um questionário restrito. Este loggin deve conter apenas letras e números. Já a senha deve conter pelo menos uma letra, um número e um caracter alfanumérico, além disso a senha deve conter exatamente oito caracteres.
Após acessar o questionário o usuário deverá responder questões comuns e também responder a questão mais importante e que dá nome ao questionário. Tudo isso, é claro, será validade com a utilização de expressões regulares e das funções da base do R e também do pacote stringr. Questões utilizadas no questionário:
- Nome
- Sexo
- Idade
- CPF
- Cidade
- Estado
- CEP
- Telefone com DDD
- Você considera o R uma ferramenta poderosa?
A ferramenta abaixo utiliza expressões regulares para consolidar as entradas de um questionário. Este questionário não está com todas as funcionalidades e possivelmente contenha erros. Caso encontre algum erro, me envie um e-mail (douglasrm.azevedo@gmail.com).
Para executar a aplicação clique aqui e baixe o código.
Existem muitos outros aspectos a serem estudados no mundo das expressões regulares. Além disso, o uso das ferramentas de manipulação de strings é estremamente útil em diversos casos. Espero que este documento sirva como uma primeira leitura para interessados em expressões regulares.