Regex

Preview:

DESCRIPTION

Uma introdução a expressões regulares e bibliotecas regex.

Citation preview

Regexa.k.a. RegExp

Verifica se número é primo

^1?$|^(11+?)\1+$

Verifica se número é primo

Isso não é uma expressão regular

^1?$|^(11+?)\1+$

Verifica se número é primo

Isso não é uma expressão regular(mas é aceito por quase todas bibliotecas

regex)

^1?$|^(11+?)\1+$

Verifica se número é primo

Isso não é uma expressão regular(mas é aceito por quase todas bibliotecas

regex)É difícil de entender

^1?$|^(11+?)\1+$

Verifica se número é primo

Isso não é uma expressão regular(mas é aceito por quase todas bibliotecas

regex)É difícil de entenderÉ fácil de errar

^1?$|^(11+?)\1+$

Verifica se número é primo

Isso não é uma expressão regular(mas é aceito por quase todas bibliotecas

regex)É difícil de entenderÉ fácil de errarÉ extremamente compacta

^1?$|^(11+?)\1+$

Verifica se número é primo

Isso não é uma expressão regular(mas é aceito por quase todas bibliotecas

regex)É difícil de entenderÉ fácil de errarÉ extremamente compactaNa verdade, checa se número não é primo

^1?$|^(11+?)\1+$

HistóricoConceito matemático introduzido na década de

50SNOBOL implementou pattern matching, mas

não expressões regularesKen Thompson introduzir expressões regulares

no editor QED, depois ed (Unix), e finalmente grep (abreviação do comando g/re/p do ed)

Padronizado pelo POSIXRepadronizado pelo Perl e Tcl (baseado em

biblioteca de Henry Spencer)Biblioteca PCRE (Philip Hazel)

Para que servem Regex?Verificar se um determinado padrão ocorre em

um textoVerificar se um determinado padrão não ocorre

em um textoLocalizar as ocorrências de um padrãoObter as ocorrências de um padrãoObter partes das ocorrências de um padrãoSubstituir ocorrências de um padrão por outro

texto, possivelmente usando partes da ocorrênciaDividir texto de acordo com um padrão

ExemplosAcha linhas com configurações:

grep "^ *[^# ]" php.iniAcha linhas que não estejam em branco:

grep –v "^$" .profile Índice de todas palavras em um texto:

[w.start() for w in re.finditer(r'\b\w', text)]Todas palavras de um texto:

@words = $text =~ /\w+/Dia, mês e ano de uma data:

($d, $m, $a) = text =~ /(\d\d)/(\d\d)/(\d{4})/Remove espaços do fim da linha:

sed -p'' -e 's/ *$//‘Divide linha em palavras e símbolos

text split """\b\s*|\s*\b"""

Expressões RegularesDescrevem Linguagens RegularesMesmo poder expressivo de Gramáticas

RegularesMesmas linguagens aceitas por Autômatos

Finitos DeterminísticosLivres de ContextoExemplo de linguagem não regular:

Número de b depende do número de a: anbn

Autômatos Finitos Determinísticos

0 1

\n

[^\n]

\n

[^\n]

Texto termina em \n?

Regex:.*\n$

Dois switches e um loop// Texto termina em \n?int state = 0;while(ch = getc()) { switch(state) { case 0: switch(ch) { case '\n': state = 1; break; default : break; } case 1: switch(ch) { case '\n': break; default : state = 0; break; } }}return state == 1;

Estrutura de uma RegexComposta de:

Um caracter (literal)Ou nada (string vazia)Ou uma composição de uma ou duas outras

regex

Operações de ComposiçãoDa maior precedência para a menor:

Repetição (kleene star): r*Concatenação: r1 r2

Alternativa: r1 | r2

Todas expressões regulares podem ser compostas a partir desses elementos

Muitas regex não podem ser compostas só com esses elementos

Tipos de RegexPOSIX Basic Regex (grep)POSIX Extended Regex (grep –E)Preg (Perl regex)PCRE (Perl Compatible(*) Regular

Expression)(*) Só que não

Etc... (cada biblioteca tem suas particularidades)

Regex Compilado vs JITCompilar um regex transforma a string

representando o regex em uma estrutura de dados otimizada para seu usoDisponível com Java, Perl, Python, Ruby

Regex Just In Time recompilam a expressão todas as vezes, para diminuir a cerimônia de seu usoDisponível com Java(*), Perl, PHP, Python, Ruby

(*) Somente para alguns usos

Outras operações de ComposiçãoQualquer caracter: .Qualquer um de um conjunto: [r1r2-r3]

Qualquer um não em um conjunto: [^r1r2]Classes de caracteres: [[:alpha:]], \w,Negação de classes: [^[:alpha:]], \WClasses POSIX: \p{Upper}, \P{InGreek}Zero ou um: r?Um ou mais: r+Entre n e m repetições: r{n, m}

Classes úteis[:alnum:]\w – inclui sublinhado (não palavras como \W)[:alpha:][:blank:][:cntrl:][:digit] ou \d (não dígito como \D)[:graph:][:lower:][:print:][:punct:][:space:] ou \s (não espaço como \S)[:upper:][:xdigit:]

GreedinessAs expressões r* e r+ retornam a maior

quantidade possível de caracteres que satisfaçam a expressão

Elas são greedy – gananciosasAlgumas bibliotecas suportam relutância:

r*? e r+?Elas retornam a menor quantidade

possível de caracteres que satisfaçam a expressão

Em alguns casos, a performance das repetições relutantes é muito superior

Relembrando PrecedênciaLembrando a precedência: repetição,

concatenação e alternativaTextos que satisfazem a expressão ab*|cd:

aababbcd

Os textos abab e acd não satisfazem a expressão

AgrupamentoPOSIX Basic Regular Expression: \( e \)Todo o resto: ( e )Grupos também capturam o conteúdo, e

podem ser extraídos separadamente ou usados na substituição

Sem captura(*): (?:r)(*) as partes de uma ocorrência

correspondentes a expressões dentro de parênteses são retornadas como grupos ou subgrupos

ContextoEu falei que expressões regulares são linguagens

sem contextoMas esses “contextos” são válidos, pois podem ser

representados como estadosÂncoras:

Início do texto ou de uma linha: ^Fim do texto ou de uma linha: $

Borda de palavras: \b ou \< e \> (POSIX BRE)Look-ahead: (?=r)Look-behind: (?<=r)Negações: (?!r) e (?<!r)

Contexto de verdadeNão suportados por expressões regularesSuportados por quase todas bibliotecas regexPodem levar a tempos exponenciaisBack references: \n (para n de 1 a 9)

Alterações de ComportamentoFormato:

Ativa/Desativa: (?idmsux-idmsux)Somente para o subgrupo: (?idmsux-idmsux:r)

Flags:Case insensitive: iUnix new lines: dMultiline: m“.” pega new lines: sUnicode-aware: uComentários: x

Escaping (citando caracteres)PCRE:

\ antes de símbolos cita o símbolo\ antes de letras tem tem significado especial

POSIX Basic RE: uma zona – consulte o manual

Citando um grupo de caracters:\Qgrupo de caracteres\E

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Revisitando Números Primos^1?$|^(11+)\1+$

CaracteresÂncoras

Alternativas

Agrupamento Back ReferenceRepetições

Concatenação

Explicando Números Primos(?x) # Dado uma sequência de dígitos 1, aceita se o # tamanho da sequência não for um número primo

# Primeiro caso, números menores que 2^ # Início da string1? # 0 ou 1 ocorrênicas do dígito 1$ # Fim da String

| # Segundo caso, números maiores ou igual a 2 # Verifica se a string pode ser reduzida a # XX...X, onde X é uma string de tamanho fixo # com dois ou mais dígitos 1

^ # Início da string( # Início do primeiro subgrupo -- o “X” da questão11+? # Sequência de dois ou mais dígitos 1 # A sequência acima é relutante por questões de performance) # Fim da sequência\1+ # Uma ou mais (novas) ocorrências do subgrupo 1$ # Fim da string

E-mail regex

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

XML Regex

Moral da HistóriaCoisas que não são regex as vezes podem ser

resolvidas com regexCoisas que são regex as vezes não valem a

pena serem resolvidas com regexAlgumas coisas não são regex e não são

resolvidas com regexResolver com código expressões regulares

simples é muito mais complicado do que as pessoas assumem

Não usem regex com xml!

Criando e Testando RegexRegexBuddy (produto comercial): o melhor

de todosDFA/Regex:

http://osteele.com/tools/reanimator/.Net:

http://www.nregex.com/nregex/default.aspxJava: http://www.myregexp.com/JavaScript: http://www.regexpal.com/Perl: http://www.regextester.com/ (tb PHP,

POSIX)PHP: http://regex.larsolavtorvik.com/ (tb

Javascript)Python: http://www.pythonregex.com/Ruby: http://www.rubular.com/

Exemplo Javaimport java.util.regex.Pattern;import java.util.regex.Matcher;

Pattern pattern = Pattern.compile("pattern");Matcher matcher = pattern.matches("text");

Matcher.find(); matcher.matches();

matcher.replaceFirst("replacement"); matcher.replaceAll(Matcher.quoteReplacement("replacement"));

MatchResult matchResult = matcher.toMatchResult();

text.split("pattern");

Exemplo Python# Compila & Buscaprog = re.compile(r"pattern")result = prog.match("text")# Atalhoresult = re.match(r"pattern", "text")

re.search("text") re.findall("text"); re.finditer("text")

re.sub("replacement", "text")

re.split("text")

The End