Trilhas
/
Julia
Julia
/
Exercícios
/
Níveis de log
Níveis de log

Níveis de log

Exercício de aprendizagem

Introdução

Uma String em Julia é uma sequência ordenada de caracteres. Como o manual aponta: "É claro que o verdadeiro problema surge quando alguém pergunta o que é um caractere."

Muito dessa complexidade será abordada em mais detalhes no Conceito Chars, mas, resumidamente:

  • Todas as strings em Julia são Unicode.
  • Strings que também são ASCII (as letras inglesas de A a Z em maiúsculas e minúsculas, os dígitos e alguns caracteres de pontuação) são fáceis de usar.
  • A maioria dos outros sistemas de escrita do mundo é possível de usar, mas exige mais cuidado.

Literais de string

Em geral, as strings são delimitadas por aspas duplas " ". As aspas simples ' ' são usadas apenas para Chars.

Também é possível usar aspas duplas triplas """ """, o que permite usar " dentro da string sem escapá-lo. Mais importante ainda: a indentação extra indesejada é removida das strings de várias linhas.

julia> """
       Multiline
       
       """
"Multiline\nString\n"

Escapar caracteres

Como a maioria das linguagens a partir do C, Julia usa uma barra invertida \ para escapar:

  1. Para inserir caracteres que não são impressos, como o caractere de nova linha \n do exemplo anterior.
  2. Para proteger caracteres que, de outra forma, teriam um significado especial, como \$ (veja abaixo).

Indexação

Em princípio, strings podem ser indexadas exatamente como vetores:

julia> s[1], s[5]
('J', 'a')

Isso claramente funciona para uma string ASCII como "Julia", mas ignora a maioria das línguas do mundo.

Considere um dos caracteres de Beowulf, escrito em inglês antigo há cerca de 15 séculos.

"Hrōðgār" claramente tem 7 caracteres, mas nem todos são ASCII.

julia> king = "Hrōðgār"
"Hrōðgār"

julia> length(king)
7

julia> isascii(king)
false

# collect() converts to a Char vector:
julia> collect(king)
7-element Vector{Char}:
 'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)
 'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
 'ō': Unicode U+014D (category Ll: Letter, lowercase)
 'ð': Unicode U+00F0 (category Ll: Letter, lowercase)
 'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)
 'ā': Unicode U+0101 (category Ll: Letter, lowercase)
 'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)

Indexar uma string como essa começa bem, mas em algum momento quebra:

julia> king[3]
'ō': Unicode U+014D (category Ll: Letter, lowercase)

julia> king[4]
ERROR: StringIndexError: invalid index [4], valid nearby indices [3]=>'ō', [5]=>'ð'

O problema é que indexar assim conta bytes, que, para strings não ASCII, não têm uma relação de 1:1 com os caracteres. Um caractere Unicode/UTF-8 pode precisar de até 4 bytes para ser representado, e o Conceito Chars vai explorar isso mais a fundo.

Construindo strings

Concatenação

Muitas linguagens usam + como operador de concatenação de strings, mas Julia não. Pelo menos a mensagem de erro é útil.

julia> "s1 " + "s2"
ERROR: MethodError: no method matching +(::String, ::String)
The function `+` exists, but no method is defined for this combination of argument types.
String concatenation is performed with * 

julia> "s1 " * "s2"
"s1 s2"

A função string() concatena um número arbitrário de strings.

julia> string("lots ", "of ", "bits")
"lots of bits"

A função join() faz o mesmo e também aceita um vetor de strings, concatenando-as com um separador especificado (por padrão, "").

julia> join(["lots", "of", "bits"], "_")
"lots_of_bits"

Observe que as strings são imutáveis, e a concatenação envolve cópia. Assim, concatenações repetidas dentro de um laço são ineficientes, e é melhor reunir os fragmentos em um vetor e juntá-los todos no final.

Repetição

Simples:

julia> repeat("Abc", 5)
"AbcAbcAbcAbcAbc"

Interpolação

Muitas linguagens têm uma forma de inserir valores calculados em strings, embora haja uma discordância extraordinária sobre a melhor sintaxe a usar.

Em Julia, os valores interpolados são precedidos por $.

julia> myvar = 42
42

julia> "myvar evaluates to $myvar"
"myvar evaluates to 42"

julia> r = 5.3
5.3

julia> "A circle of radius $r has area $(π * r^2)"
"A circle of radius 5.3 has area 88.24733763933729"

Os parênteses são obrigatórios quando omiti-los deixaria o código ambíguo, mas são opcionais para um único identificador seguido de espaço em branco.

Para incluir um $ na string, escape-o como \$.

Observe a limitação de que a interpolação atualmente não permite formatação, como o número de casas decimais a exibir.

@sprintf()

Para um controle mais refinado sobre a montagem de strings, Julia copia a função sprintf do C (e de várias linguagens posteriores: a Wikipédia lista cerca de 30).

Em Julia, isso é implementado como uma macro dentro do módulo Printf, daí o prefixo @.

julia> using Printf

julia> r = 5.3
5.3

julia> @sprintf("A circle of radius %.1f has area %.2f", r, π * r^2)
"A circle of radius 5.3 has area 88.25"

Funções de string

Por simplicidade, esta seção vai se concentrar nas funções que retornam uma nova string e deixam a entrada inalterada. Muitas têm uma equivalente, com o sufixo ! no nome, que modifica a entrada no lugar.

Comprimento

Qual é o comprimento de uma string? Às vezes, depende de como você conta.

O caso simples são as strings ASCII, em que cada caractere ocupa 1 byte.

julia> string_asc = "Julia"
"Julia"

julia> length(string_asc)
5

julia> sizeof(string_asc)
5

A função length() retorna o número de caracteres, e a função sizeof(), o número de bytes.

Essa distinção se torna importante com outros conjuntos de caracteres:

julia> king = "Hrōðgār"
"Hrōðgār"

julia> length(king)
7

julia> sizeof(king)
10

Divisão

Uma operação comum em programação é pegar uma string longa e dividi-la em pedaços, com base em uma string separadora de um ou mais caracteres.

De modo mais geral, usamos a função split(). O separador, por padrão, é (qualquer) espaço em branco, mas outros podem ser especificados.

julia> split("my little string")
3-element Vector{SubString{String}}:
 "my"
 "little"
 "string"

julia> split("My_snake_case_string", "_")
4-element Vector{SubString{String}}:
 "My"
 "snake"
 "case"
 "string"

Esses exemplos dividem uma string em strings menores. Dividir uma string em caracteres é uma operação diferente.

Localizar e substituir

Uma string contém uma substring especificada? Curiosamente, há duas funções para testar isso: occursin() e contains() diferem apenas na ordem de seus argumentos.

julia> needle = "Julia"
"Julia"

julia> haystack = "Python, Julia and R"
"Python, Julia and R"

julia> occursin(needle, haystack)
true

julia> contains(haystack, needle)
true

Para ser mais específico quanto à posição:

julia> startswith(haystack, "Python")
true

julia> endswith(haystack, "Python")
false

Para obter os índices início:fim de uma substring, temos várias funções:

  • findfirst()
  • findlast()
  • findprev()
  • findnext()
julia> findfirst(needle, haystack)
9:13

Para substituir substrings, liste as mudanças usando a sintaxe x => y.

julia> replace("abc", "a"=>"b", "b"=>"c", "c"=>"a")
"bca"

Desde o Julia 1.7, a função replace pode receber um número arbitrário de mudanças, com a garantia de que nenhum caractere será alterado mais de uma vez durante a substituição.

A sintaxe x => y é chamada de pair, um tipo importante em Julia, abordado em mais detalhes no Conceito Dicts and Pairs.

Espaços em branco

Muitas vezes precisamos remover espaços em branco do início e/ou do fim de uma string.

As funções para isso são lstrip() (esquerda), rstrip() (direita) e strip() (ambos).

julia> strip("\n\t  useful_bit\n\n")
"useful_bit"

Alterar maiúsculas e minúsculas

Essas funções têm nomes bastante autoexplicativos:

julia> s = repeat("aBcD ", 5)
"aBcD aBcD aBcD aBcD aBcD "

julia> uppercase(s)
"ABCD ABCD ABCD ABCD ABCD "

julia> lowercase(s)
"abcd abcd abcd abcd abcd "

julia> titlecase(s)  # Initial letter of each word uppercase
"Abcd Abcd Abcd Abcd Abcd "

Instruções

Neste exercício você vai processar linhas de log.

Cada linha de log é uma string formatada assim: "[<LEVEL>]: <MESSAGE>".

Existem três níveis de log diferentes:

  • INFO
  • WARNING
  • ERROR

Você tem três tarefas, e cada uma delas recebe uma linha de log e pede que você faça algo com ela.

1. Obter a mensagem de uma linha de log

Implemente a função message para retornar a mensagem de uma linha de log:

julia> message("[ERROR]: Invalid operation")
"Invalid operation"

Qualquer espaço em branco no início ou no fim deve ser removido:

julia> message("[WARNING]:  Disk almost full\r\n")
"Disk almost full"

2. Obter o nível de log de uma linha de log

Implemente a função log_level para retornar o nível de log de uma linha de log, que deve ser retornado em minúsculas:

julia> log_level("[ERROR]: Invalid operation")
"error"

3. Reformatar uma linha de log

Implemente a função reformat, que reformata a linha de log colocando a mensagem primeiro e o nível de log depois dela, entre parênteses:

julia> reformat("[INFO]: Operation completed")
"Operation completed (info)"

Observação: Todas as strings deste exercício estão em inglês e limitadas ao conjunto de caracteres ASCII. Os próximos Conceitos darão a chance de trabalhar com caracteres Unicode.

Editar via GitHub O link abre em uma nova janela ou aba
Julia Exercism

Tudo pronto para começar Níveis de log?

Crie sua conta no Exercism para aprender e dominar Julia com 35 conceitos128 exercícios e mentoria humana de verdade, tudo de graça.