Percursos
/
Julia
Julia
/
Programa
/
Expressões regulares
Ex

Expressões regulares em Julia

4 exercícios

Sobre Expressões regulares

As expressões regulares são uma forma extremamente versátil de fazer correspondência de padrões em strings, recorrendo a uma Linguagem de Domínio Específico (DSL) concebida para esse fim.

Tal como várias outras linguagens de programação, a Julia não tenta implementar a sua própria biblioteca de expressões regulares. Em vez disso, usa a popular biblioteca PCRE2, o que lhe dá uma sintaxe de expressões regulares idêntica à de (por exemplo) Gleam e muito semelhante à de JavaScript.

Note

Este programa de estudos da Julia pressupõe que já conheces a sintaxe básica de expressões regulares. Vamos concentrar-nos exclusivamente nas funcionalidades específicas da Julia.

Abaixo estão listados alguns recursos para refrescares os teus conhecimentos de expressões regulares.

A interface da Julia para expressões regulares está descrita no manual.

Uma expressão regular em Julia é simplesmente uma string precedida de r antes das aspas de abertura ". Toda a funcionalidade básica faz parte da biblioteca padrão.

De facto, muitas das funções já abordadas no Conceito Strings são concebidas, por predefinição, para pesquisas com expressões regulares, como occursin().

julia> re = r"test$"
r"test$"

julia> typeof(re)
Regex

# Does a string end with "test"?
julia> occursin(re, "this is a test")
true

julia> occursin(re, "these are tests")
false

Após as aspas de fecho podem vir caracteres modificadores, como o i para uma correspondência que não distingue maiúsculas de minúsculas.

julia> occursin(r"test", "Testing")
false

julia> occursin(r"test"i, "Testing")
true

Capturas

Muitas vezes, queremos saber o que corresponde ao padrão. Isso consegue-se incluindo grupos de captura entre parênteses dentro da expressão regular e usando depois a função match().

julia> m = match(r"(\d+g) .* (\d+ml)", "dissolve 25g sugar in 200ml water")
RegexMatch("25g sugar in 200ml", 1="25g", 2="200ml")

julia> m.captures
2-element Vector{Union{Nothing, SubString{String}}}:
 "25g"
 "200ml"

# how many matches?
julia> length(m.captures)
2

# what matched?
julia> m[1], m[2]
("25g", "200ml")

# Starting positions of the matches (character index)
julia> m.offsets
2-element Vector{Int64}:
 10
 23

Claro que uma correspondência pode falhar. Nesse caso, o resultado é o valor especial Nothing em vez de um RegexMatch, por isso prepara-te para testar isso.

# failed match
m = match(r"(not here)", "dissolve 25g sugar in 200ml water")

julia> typeof(m)
Nothing

julia> isnothing(m)
true

Embora, por predefinição, match comece no início da string, também podemos indicar um deslocamento n para ignorar os primeiros n carateres.

# capture first match
julia> m = match(r"(\wat)", "cat, sat, mat")
RegexMatch("cat", 1="cat")

# ignore first 5 characters, then match
julia> m = match(r"(\wat)", "cat, sat, mat", 5)
RegexMatch("sat", 1="sat")

Na Julia, match() só encontra a primeira correspondência dentro da string de destino: não existe um modificador global como nalgumas outras linguagens.

Em vez disso, temos eachmatch(), que devolve um iterador de correspondências. A avaliação é preguiçosa, por isso podes ter de o converter no formato que pretendes.

julia> matches = eachmatch(r"(\wat)", "cat, sat, mat")
Base.RegexMatchIterator{String}(r"(\wat)", "cat, sat, mat", false)

# convert to vector
julia> collect(matches)
3-element Vector{RegexMatch}:
 RegexMatch("cat", 1="cat")
 RegexMatch("sat", 1="sat")
 RegexMatch("mat", 1="mat")

# convert with comprehension
julia> [m.match for m in matches]
3-element Vector{SubString{String}}:
 "cat"
 "sat"
 "mat"

# broadcast an anonymous function
julia> (m -> m.match).(matches)
3-element Vector{SubString{String}}:
 "cat"
 "sat"
 "mat"

Por predefinição, não são permitidas correspondências sobrepostas. Acrescenta overlap = true como argumento de palavra-chave para alterar este comportamento.

julia> eachmatch(r"aba", "abababa") |> collect  # matches at positions 1, 5
2-element Vector{RegexMatch}:
 RegexMatch("aba")
 RegexMatch("aba")

julia> eachmatch(r"aba", "abababa"; overlap = true) |> collect  # also matches at position 3
3-element Vector{RegexMatch}:
 RegexMatch("aba")
 RegexMatch("aba")
 RegexMatch("aba")

Substituir

Uma razão frequente para usar uma expressão regular é substituir a correspondência por uma string diferente.

A função replace() foi abordada no Conceito Strings, onde usámos literais de string para pesquisar. A mesma função pode tirar partido de todo o poder da correspondência com expressões regulares.

julia> replace("some string", r"[aeiou]" => "*")
"s*m* str*ng"

julia> replace("first second", r"(\w+) (?<agroup>\w+)" => s"\g<agroup> \1")
"second first"

O segundo exemplo acima mostra como se podem usar grupos de captura numerados e nomeados na substituição, dentro de uma string s" ".

Consulta o manual para mais detalhes: este é um tema que obriga constantemente a maioria dos programadores a voltar à documentação!

Editar via GitHub A ligação abre numa nova janela ou separador

Aprende Expressões regulares

A prática está bloqueada

Desbloqueia mais 3 exercícios para praticares Expressões regulares