Trilhas
/
Go
Go
/
Exercícios
/
Logs, logs, logs!
Logs, logs, logs!

Logs, logs, logs!

Exercício de aprendizagem

Introdução

O tipo rune em Go é um alias para int32. Dado esse tipo int32 subjacente, o tipo rune armazena um valor inteiro de 32 bits com sinal. No entanto, diferentemente de um tipo int32, o valor inteiro armazenado em um tipo rune representa um único caractere Unicode.

Unicode e pontos de código Unicode

Unicode é um superconjunto do ASCII que representa caracteres atribuindo um número único a cada caractere. Esse número único é chamado de ponto de código Unicode. Unicode tem como objetivo representar todos os caracteres do mundo, incluindo diversos alfabetos, números, símbolos e até emojis, como pontos de código Unicode.

Em Go, o tipo rune representa um único ponto de código Unicode.

A tabela a seguir mostra exemplos de caracteres Unicode junto com seus pontos de código Unicode e valores decimais:

Caractere Unicode Ponto de código Unicode Valor decimal
0 U+0030 48
A U+0041 65
a U+0061 97
¿ U+00BF 191
π U+03C0 960
🧠 U+1F9E0 129504

UTF-8

UTF-8 é uma codificação de caracteres de largura variável usada para codificar cada ponto de código Unicode em 1, 2, 3 ou 4 bytes. Como um ponto de código Unicode pode ser codificado em no máximo 4 bytes, o tipo rune precisa ser capaz de armazenar até 4 bytes de dados. É por isso que o tipo rune é um alias para int32, já que um tipo int32 é capaz de armazenar até 4 bytes de dados.

Os arquivos de código-fonte em Go são codificados usando UTF-8.

Usando runes

Variáveis do tipo rune são declaradas colocando um caractere entre aspas simples:

myRune := '¿'

Como rune é apenas um alias para int32, imprimir o tipo de uma rune produzirá int32:

myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32

Da mesma forma, imprimir o valor de uma rune produzirá seu valor inteiro (decimal):

myRune := '¿'
fmt.Printf("myRune value: %v\n", myRune)
// Output: myRune value: 191

Para imprimir o caractere Unicode representado pela rune, use o verbo de formatação %c:

myRune := '¿'
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿

Para imprimir o ponto de código Unicode representado pela rune, use o verbo de formatação %U:

myRune := '¿'
fmt.Printf("myRune Unicode code point: %U\n", myRune)
// Output: myRune Unicode code point: U+00BF

Runes e strings

As strings em Go são codificadas usando UTF-8, o que significa que elas contêm caracteres Unicode. Os caracteres em uma string são armazenados e codificados como 1, 2, 3 ou 4 bytes, dependendo do caractere Unicode que representam.

Em Go, slices são usados para representar sequências, e podemos iterar sobre eles usando range. Quando iteramos sobre uma string, Go converte a string em uma série de runes, cada uma com 4 bytes (lembre-se: o tipo rune é um alias para um int32!)

Ainda que uma string seja apenas um slice de bytes, a palavra-chave range itera sobre as runes de uma string, não sobre seus bytes.

Neste exemplo, a variável index representa o índice inicial da sequência de bytes da rune atual, e a variável char representa a rune atual:

myString := "❗hello"
for index, char := range myString {
  fmt.Printf("Index: %d\tCharacter: %c\t\tCode Point: %U\n", index, char, char)
}
// Output:
// Index: 0	Character: ❗		Code Point: U+2757
// Index: 3	Character: h		Code Point: U+0068
// Index: 4	Character: e		Code Point: U+0065
// Index: 5	Character: l		Code Point: U+006C
// Index: 6	Character: l		Code Point: U+006C
// Index: 7	Character: o		Code Point: U+006F

Como as runes podem ser armazenadas em 1, 2, 3 ou 4 bytes, o comprimento de uma string nem sempre é igual ao número de caracteres dela. Use a função embutida len para obter o comprimento de uma string em bytes e a função utf8.RuneCountInString para obter o número de runes de uma string:

import "unicode/utf8"

myString := "❗hello"
stringLength := len(myString)
numberOfRunes := utf8.RuneCountInString(myString)

fmt.Printf("myString - Length: %d - Runes: %d\n", stringLength, numberOfRunes)
// Output: myString - Length: 8 - Runes: 6

Instruções

Você recebeu a tarefa de criar uma biblioteca de log para ajudar a gerenciar os logs da sua organização. Esta biblioteca permitirá identificar qual aplicação emitiu um determinado log, corrigir logs corrompidos e determinar se uma linha de log está dentro de um certo limite de caracteres.

1. Identifique qual aplicação emitiu um log

Os logs vêm de várias aplicações, e cada uma usa o seu próprio formato de log proprietário. É preciso identificar a aplicação que emitiu um log antes de armazená-lo em um sistema de agregação de logs.

Implemente a função Application, que recebe uma linha de log e retorna a aplicação que emitiu essa linha de log.

Para identificar qual aplicação emitiu uma determinada linha de log, procure na linha de log por um caractere específico, conforme a tabela a seguir:

Aplicação Caractere Ponto de código Unicode
recommendation ❗ U+2757
search 🔍 U+1F50D
weather ☀ U+2600

Se uma linha de log não contiver nenhum dos caracteres da tabela acima, retorne default para quem chamou a função. Se uma linha de log contiver mais de um caractere da tabela acima, retorne a aplicação correspondente ao primeiro caractere encontrado na linha, da esquerda para a direita.

Application("❗ recommended search product 🔍")
// => recommendation

2. Corrija logs corrompidos

Por causa de um bug raro, mas persistente, na infraestrutura de log, certos caracteres nos logs podem acabar corrompidos. Depois de passar um tempo identificando os caracteres corrompidos e o valor original deles, você decide atualizar a biblioteca de log para ajudar a corrigir logs corrompidos.

Implemente a função Replace, que recebe uma linha de log, um caractere corrompido e o valor original, e retorna uma linha de log modificada, com todas as ocorrências do caractere corrompido substituídas pelo valor original.

log := "please replace '👎' with '👍'"

Replace(log, '👎', '👍')
// => please replace '👍' with '👍'"

3. Determine se um log pode ser exibido

Os sistemas responsáveis por exibir logs têm um limite para o número de caracteres que podem ser exibidos por linha de log. Por isso, as pessoas estão pedindo que esta biblioteca inclua uma função auxiliar para determinar se uma linha de log está dentro de um limite específico de caracteres.

Implemente a função WithinLimit, que recebe uma linha de log e um limite de caracteres e retorna se a linha de log está ou não dentro do limite de caracteres.

WithinLimit("hello❗", 6)
// => true
Editar via GitHub O link abre em uma nova janela ou aba
Go Exercism

Tudo pronto para começar Logs, logs, logs!?

Crie sua conta no Exercism para aprender e dominar Go com 34 conceitos165 exercícios e mentoria humana de verdade, tudo de graça.