Golang – 06. Biblioteca Padrão I – fmt e strings

Este artigo é a parte 6 de 11 na série Golang

No universo da programação, a escolha de uma linguagem de programação é frequentemente influenciada pela riqueza de sua biblioteca padrão. Por exemplo, o Python é renomado pelo lema “batteries included”, que evidencia sua vasta biblioteca padrão, capacitando os desenvolvedores a construir uma ampla gama de produtos de maneira eficiente. Uma expectativa semelhante recai sobre qualquer linguagem moderna, especialmente considerando a diversidade e a maturidade das linguagens já estabelecidas no mercado. Desde o seu surgimento, os criadores de Go (ou Golang) têm se dedicado a fornecer um ecossistema robusto para o desenvolvimento de aplicativos, equipado com ferramentas contemporâneas e essenciais para qualquer tipo de projeto.

A lista completa de pacotes inclusos em Go está disponível na página pkg.go.dev/std e também em alguns repositórios alternativos com formatação aprimorada, como o Devdocs.io/go. Neste artigo, fornecerei uma visão geral de alguns pacotes da biblioteca padrão que julgo serem particularmente significativos e aqueles que prevejo utilizar extensivamente no futuro. Além disso, pretendo incluir informações adicionais sobre outros pacotes imprescindíveis da biblioteca padrão em futuras edições.

Pacote fmt

O pacote fmt provê uma série de funcionalidades para formatação de valores de entrada e saída em Go, com suas funções assemelhando-se às conhecidas printf e scanf da linguagem C.

Códigos de Formatação

A tabela a seguir apresenta os principais códigos de formatação utilizados com o pacote fmt:

CódigoDescrição
%%caractere porcentagem (%)
%vformatação padrão para o tipo passado
%T imprime o tipo passado do valor passado
%sstring
%fdecimal de ponto flutuante
%e ou %Enotação científica
%qstring entre duplas aspas
%co caractere representado pelo Unicode
%dinteiro decimal (base 10)
%o e %Obase 8 e base 8 com prefixo “0o”
%x e %Xbase 16 e base 16 com a-f capitalizado
%tbooleano (true/false)

Para ilustrar a aplicação desses códigos, o código Go a seguir implementa alguns deles:

package main

import "fmt"

func main() {
    var (
        a int64   = 2
        b uint16  = 8
        c float64 = 2.43342325
        d bool    = true
        e byte    = 'a'
        f string  = "albert"
    )

    fmt.Printf("a: %v %T\n", a, a)
    fmt.Printf("b: %v %T\n", b, b)
    fmt.Printf("c: %v %T\n", c, c)
    fmt.Printf("d: %v %T\n", d, d)
    fmt.Printf("e: %v %T\n", e, e)
    fmt.Printf("f: %v %T\n", f, f)

    fmt.Println()

    fmt.Printf("%%d format in a: %03d**%+3d\n", a, a)
    fmt.Printf("%%d format in e: %02d  %+2d\n", e, e)
    fmt.Printf("%%f format in c: %1.1f  %.2f\n", c, c)
    fmt.Printf("%%q format in e and f:%q %q\n", e, f)
    fmt.Printf("%%o and %%O format in d:%o %O\n", b, b)
    fmt.Printf("%%s format in f: >|%s|<    >|%8s|<\n", f, f)
}

A saída do código é a seguinte:

Bash

rudson@suzail:format$ go run geral.go
a: 2 int64
b: 8 uint16
c: 2.43342325 float64
d: true bool
e: 97 uint8
f: albert string

%d format in a: 002** +2
%d format in e: 97 +97
%f format in c: 2.4 2.43
%q format in e and f:’a’ “albert”
%o and %O format in d:10 0o10
%s format in f: >|albert|< >| albert|<

Como demonstrado, é possível especificar a largura do campo de saída adicionando um número após o símbolo “%“, tanto para números quanto para strings.

Com números, é possível exibir o sinal (positivo ou negativo) usando o sinal “+” logo após o “%“, como em %+3d. Para strings, o sinal “+” força que a saída para %q (ou %+q) represente apenas caracteres ASCII.

Para números de ponto flutuante, você pode limitar o número de casas decimais após o ponto com a notação %.nf, onde n é o número de dígitos desejados após o ponto decimal.

Essas formatações são similares às da linguagem C e são usadas com funções do pacote fmt que terminam com “f“, como Printf, scanf, Errorf, Fprintf e Sscanf.

Existem outras nuances nos códigos de formatação que não foram abordadas aqui, mas as apresentadas são essenciais para a maioria dos usos. Para um entendimento mais aprofundado, recomenda-se a consulta à documentação oficial.

Funções Print, Printf e Println

As funções Print, Printf e Println do pacote fmt constituem os métodos padrão de impressão na tela em Go. A função Print executa a impressão na formatação padrão do tipo empregado. Já a função Println é similar, mas adiciona uma quebra de linha ao final da impressão.

Exemplo de Uso:

package main

import "fmt"

func main() {
    nome, sobrenome := "Alberto", "Santos"
    idade := 35

    fmt.Print(nome, " ", sobrenome)
    fmt.Println(" possui", idade, "anos.")
    fmt.Println("Fim")
}

A saída deste código será:

Bash

rudson@suzail:format$ go run prints.go
Alberto Santos possui 35 anos.
Fim

Para uma formatação mais controlada, você pode usar Printf, que permite especificar a formatação desejada. Por exemplo, as linhas 9, 10 e 11 do código anterior poderiam ser substituídas por:

...
    fmt.Printf("%s %s possui %d anos.\nFim\n", nome, sobrenome, idade)
}

Retorno das Funções Print

A assinatura de uma função, que inclui sua linha de declaração, é instrutiva para entender as entradas e saídas esperadas. Por isso, as assinaturas das funções Print, Printf e Println são apresentadas no início desta seção. Note que o tipo any é usado nas assinaturas para indicar que essas funções aceitam uma sequência de argumentos de tipos variados. any é um alias para interface{}, o que significa que pode aceitar qualquer tipo.

func Print(a ...any) (n int, err error)
func Println(a ...any) (n int, err error)
func Printf(format string, a ...any) (n int, err error)

As entradas dessas funções são variádicas, indicadas por a ...any, permitindo uma sequência de argumentos de tipos variados. Apenas Printf difere um pouco, iniciando com uma string de formatação. O retorno dessas funções inclui um inteiro n, que representa o número de bytes impressos, e um código de erro err, caso ocorra algum problema durante a impressão.

Em Go, é possível ignorar completamente o retorno de uma função ou parte dele. Por exemplo, você pode ignorar o número de bytes impressos e capturar apenas o erro:

...
	_, err := fmt.Printf("%20s -> %2d", a, j)

No comando acima, o número de bytes impressos é ignorado e o erro, se houver, é armazenado na variável err. Se err == nil, a impressão foi bem-sucedida; caso contrário, err conterá o código do erro gerado.

Embora seja possível rastrear erros nas funções de impressão, é comum invocá-las sem capturar os retornos, especialmente em contextos onde a precisão da saída não é crítica.

Funções Scan, Scanf e Scanln

As funções Scan, Scanf e Scanln do pacote fmt são usadas para ler a entrada do usuário a partir do teclado, de maneira similar às funções de impressão.

Separadores Espaço e Quebra de Linha

A função Scan trata tanto os espaços quanto as quebras de linha como separadores. Por exemplo, a seguinte chamada de função:

...
    fmt.Scan(&a, &b, &c, &d)

com a, b, c e d sendo variáveis do tipo inteiro, aceitará tanto a entrada “1 2 3 4” (quatro números separados por espaços na mesma linha), quanto qualquer combinação de quatro números, cada um seguido por um espaço ou uma quebra de linha.

Em contraste, a função Scanln interrompe a leitura na primeira quebra de linha encontrada. Por exemplo, com a entrada:

1 2
3
4

Scan funcionaria corretamente, mas Scanln atribuiria 1 e 2 às variáveis a e b respectivamente, e deixaria c e d com valores zero, pois a leitura é interrompida na quebra de linha após “1 2“.

A função Scanf, por outro lado, lê a entrada de acordo com um formato específico. As quebras de linha precisam ser explicitamente incluídas na string de formatação. Por exemplo, o código:

...
    fmt.Scanf("%d %d\n%d\n%d", &a, &b, &c, &d)

lerá a entrada específica mostrada anteriormente, mas falhará com qualquer outra entrada diferente. A quantidade de espaços entre os números não é significativa para Scanf.

Para entender melhor como essas funções lidam com a entrada, experimente diferentes entradas no código a seguir:

package main

import "fmt"

func main() {
    var a, b, c, d int64

    fmt.Println("Entre com quatro valores: ")
    fmt.Scan(&a, &b, &c, &d)
    fmt.Printf("a:%d  b:%d  c:%d  d:%d\n", a, b, c, d)

    fmt.Println("\nEntre com três valores na forma %%d %%d<ENTER> %%d %%d<ENTER>: ")
    fmt.Scanf("%d %d\n %d %d\n", &a, &b, &c, &d)
    fmt.Printf("a:%d  b:%d  c:%d  d:%d\n", a, b, c, d)

    fmt.Println("\nEntre com quatro valores na forma com um \\n: ")
    fmt.Scanln(&a, &b, &c, &d)
    fmt.Printf("a:%d  b:%d  c:%d  d:%d\n", a, b, c, d)
}

Retorno das Funções Scan

Diferentemente das funções de impressão, os retornos das funções Scan são cruciais para verificar se a entrada foi lida com sucesso. As assinaturas das funções Scan, Scanln e Scanf são:

func Scan(a ...any) (n int, err error)
func Scanln(a ...any) (n int, err error)
func Scanf(format string, a ...any) (n int, err error)

O valor retornado n indica o número de itens lidos com sucesso, e err é o código de erro, se houver. O código a seguir mostra como verificar os retornos dessas funções para garantir que a entrada correta seja capturada:

package main

import "fmt"

func main() {
    var a, b, c, m int

    for {
        fmt.Println("\nEnter com os valores de a b c<ENTER>")
        n, err := fmt.Scanln(&a, &b, &c)
        if err == nil {
            m = n
            break
        }
        fmt.Printf("Entrou %d e esperado 3 entradas. Erro:%v\n", n, err)
    }

    fmt.Printf("Entrou com %d números, de valores: a = %d, b = %d e c = %d\n", m, a, b, c)
}

Funções Sprint, Sprintln e Sprintf

As funções Sprint, Sprintln e Sprintf são utilizadas para construir strings com base nos argumentos fornecidos. Elas são particularmente úteis para formatar strings e construir mensagens. Suas assinaturas são:

func Sprint(a …any) string
func Sprintln(a …any) string
func Sprintf(format string, a …any) string

Essas funções são amplamente usadas para montar strings. Sprintf, em particular, é muito versátil, permitindo formatar a string de saída de maneira detalhada. Um uso comum de Sprintf é definir a representação em string de tipos personalizados, como demonstrado no exemplo a seguir:

package main

import "fmt"

type pessoa struct {
    nome      string
    sobreNome string
    idade     int
}

func (p pessoa) String() string {
    return fmt.Sprintf("O %s %s possui %d anos.", p.nome, p.sobreNome, p.idade)
}

func main() {
    a := pessoa{
        nome:      "Alonso",
        sobreNome: "Bortolini",
        idade:     36,
    }

    fmt.Print(a)
}

Neste exemplo, a função padrão de impressão para o tipo pessoa é sobrescrita, usando fmt.Sprintf para formatar a string resultante. A execução deste código resulta em uma saída mais legível e personalizada para o tipo pessoa:

O Alonso Bortolini possui 36 anos.

Em suma, Sprint e Sprintln retornam uma string com a representação padrão dos tipos passados como argumentos, enquanto Sprintln adiciona uma quebra de linha ao final. Por outro lado, Sprintf permite construir uma string formatada, aproveitando os códigos de formatação que foram apresentados anteriormente.

Função Errorf

A função Errorf é usada para criar mensagens de erro personalizadas e formatadas. Sua assinatura é:

func Errorf(format string, a ...any) error

Errorf é extremamente útil para gerar mensagens de erro específicas, tornando a depuração e o tratamento de erros mais claros. O seguinte exemplo ilustra seu uso:

package main

import (
    "fmt"
    "log"
)

type user struct {
    name string
    id   int
}

func main() {
    u := user{"alves", 1001}

    err := fmt.Errorf("Usuário %s (id %d) não encontrado", u.name, u.id)

    log.Fatal(err)
}

É importante observar que, seguindo as convenções do Go, as mensagens de erro devem começar com letra minúscula e não devem terminar com pontuação. A execução deste código gerará a seguinte saída:

Bash

rudson@suzail:~$ go run fmt_errorf
2022/05/16 10:16:28 Usuário alves (id 1001) não encontrado
exit status 1
rudson@suzail:~$ echo $?
1

O último comando no terminal, echo $?, exibe o código de saída do programa. Um código de saída 0 indica que o programa foi executado com sucesso, enquanto um código diferente de zero sugere a ocorrência de algum erro. Neste caso, o código 1 indica que houve um erro no programa.

Como ler Strings com espaços no fmt?

Embora o pacote fmt seja versátil e forneça várias funções para leitura e escrita de dados, ele não oferece uma maneira direta de ler strings com espaços a partir do teclado. Isso pode ser uma limitação quando se trata de ler entradas como nomes completos ou endereços, que naturalmente contêm espaços.

Para contornar essa limitação, você pode utilizar uma combinação do pacote bufio com o pacote os para ler diretamente do buffer de entrada. O exemplo a seguir demonstra como fazer isso:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    fmt.Println("Nome completo:")

    scanner := bufio.NewReader(os.Stdin)
    line, _ := scanner.ReadString('\n')

    fmt.Printf("%q %T\n", line, line)
}

Este código lê a entrada do teclado até que a tecla Enter (\n) seja pressionada. A função scanner.ReadString('\n') garante que a leitura continue até que uma quebra de linha seja encontrada. A saída para a entrada “Alberto Santos Dumont” seria:

Bash

rudson@suzail:~$ go run exemplo.go
Seu nome completo:
Alberto Santos Dumont
“Alberto Santos Dumont\n” string

Note que o caractere de quebra de linha (\n) também é capturado. Uma discussão mais aprofundada sobre o pacote bufio será realizada em futuros artigos.

Pacote Strings

O pacote strings provê uma ampla gama de funções para manipulação de strings em Go. Devido à sua extensa lista de funcionalidades, vou apresentar as principais funções em ordem alfabética, conforme documentado oficialmente.

Função strings.Compare

func Compare(a, b string) int

A função Compare retorna 0 se as strings a e b forem iguais, -1 se a for menor que b e +1 se a for maior que b. A comparação é feita lexicograficamente, ou seja, byte a byte. Os exemplos a seguir demonstram o comportamento desta função:

...
    fmt.Println(strings.Compare("a", "b"))  // -1
    fmt.Println(strings.Compare("a", "a"))  //  0
    fmt.Println(strings.Compare("b", "ab")) //  1

Funções Contains, ContainsAny e ContainsRune

O pacote strings oferece várias funções para verificar a presença de sub-strings ou caracteres em uma string.

Função Contains

func Contains(s, ss string) bool

A função Contains verifica se a sub-string ss está contida na string s, retornando true se estiver presente. Por exemplo:

...
    fmt.Println(strings.Contains("seafood", "foo")) // true
    fmt.Println(strings.Contains("seafood", "bar")) // false
    fmt.Println(strings.Contains("seafood", ""))    // true

Uma string vazia é considerada como estando contida em qualquer string, portanto, a função retorna true nesse caso.

Função ContainsAny

func ContainsAny(s, chars string) bool

A função ContainsAny verifica se pelo menos um dos caracteres da string chars está presente na string s. Por exemplo:

...
    fmt.Println(strings.ContainsAny("failure", "aj")) // true

Função ContainsRune

func ContainsRune(s string, r rune) bool

A função ContainsRune verifica se o código rune fornecido está presente na string s. Por exemplo:

...
    fmt.Println(strings.ContainsRune("aardvark", 97)) // true

Neste caso, 97 é o código Unicode para o caractere “a“, que está presente na string “aardvark“.

Função Count

func Count(s, ss string) int

A função Count retorna o número de ocorrências da sub-string ss na string s. Por exemplo:

...
    fmt.Println(strings.Count("aardvark", "aa")) // 1
    fmt.Println(strings.Count("aardvark", "a"))  // 3

A função contabiliza quantas vezes a sub-string aparece na string principal.

Função Cut

func Cut(s, sep string) (before, after string, found bool)

A função Cut divide a string s usando o separador sep. Retorna as partes before e after separadas por sep, e found indica se o separador foi encontrado na string s. Por exemplo:

...
    b, a, f := strings.Cut("Albert Eintein", "ert")
    fmt.Printf("before: %q\n after: %q\n found: %t \n\n", b, a, f)

    b, a, f = strings.Cut("Albert Eintein", "e")
    fmt.Printf("before: %q\n after: %q\n found: %t \n\n", b, a, f)

    b, a, f = strings.Cut("Albert Eintein", "see")
    fmt.Printf("before: %q\n after: %q\n found: %t \n\n", b, a, f)

Os exemplos demonstram como a função Cut pode ser usada para separar uma string em duas partes com base em um separador especificado. O retorno deste código será:

before: "Alb"
 after: " Eintein"
 found: true 

before: "Alb"
 after: "rt Eintein"
 found: true 

before: "Albert Eintein"
 after: ""
 found: false 

Funções Index, IndexAny, IndexByte e IndexRune

O pacote strings fornece várias funções para localizar sub-strings ou caracteres dentro de uma string principal.

Função Index

func Index(s, ss string) int

Index retorna o índice da primeira ocorrência da sub-string ss dentro da string s. Se ss não for encontrada, a função retorna -1. Por exemplo:

...
    fmt.Println(strings.Index("chicken", "ken")) // 4

Função IndexAny

func IndexAny(s, chars string) int

IndexAny retorna o índice do primeiro caractere da string s que está presente na string chars. Se nenhum caractere for encontrado, retorna -1. Por exemplo:

...
    fmt.Println(strings.IndexAny("chicken", "aeiouy")) // 2

Função IndexByte

func IndexByte(s string, c byte) int

IndexByte retorna o índice da primeira ocorrência do byte c na string s. Se c não for encontrado, retorna -1. Por exemplo:

...
    fmt.Println(strings.IndexByte("gophers", 'h')) // 3

Função IndexRune

func IndexRune(s string, r rune) int

IndexRune funciona de forma semelhante a IndexByte, mas busca um rune em vez de um byte. Por exemplo:

...
    fmt.Println(strings.IndexRune("chicken", 'k')) // 4

IndexFunc e as funções unicode.Is…

IndexFunc retorna o índice do primeiro caractere em s que satisfaça a função f. Se nenhum caractere satisfizer f, retorna -1. f aceita um rune e retorna um bool.

func IndexFunc(s string, f func(rune) bool) int

Um conjunto útil de funções que podem ser usadas com IndexFunc são as funções Is... do pacote unicode, que determinam se um rune satisfaz certas propriedades. Por exemplo, unicode.IsLetter(r rune) bool retorna true se r for uma letra.

FunçãoAssinaturaTrue se rune é?
IsControlfunc IsControl(r rune) boolcaractere de controle
IsDigitfunc IsDigit(r rune) booldecimal
IsGraphicfunc IsGraphic(r rune) boolcaractere gráfico
IsLetterfunc IsLetter(r rune) boolletra
IsLowerfunc IsLower(r rune) boolcaractere minúsculo
IsNumberfunc IsNumber(r rune) boolnúmero
IsPunctfunc IsPunct(r rune) boolcaractere de pontuação
IsSpacefunc IsSpace(r rune) boolespaço
IsPrintfunc IsPrint(r rune) boolimprimível (caracteres, letras, …)
IsSymbolfunc IsSymbol(r rune) boolsímbolo
IsUpperfunc IsUpper(r rune) boolcaractere maiúsculo
Algumas funções `unicode.Is…` com assinatura `func(rune) bool`.

Um exemplo de uso de IndexFunc com funções unicode.Is...:

package main

import (
    "fmt"
    "strings"
    "unicode"
)

func main() {
    str := "A Revolução Americana, ou Revolução Americana de 1776, teve suas raízes"

    fmt.Println(strings.IndexFunc(str, unicode.IsNumber))
    fmt.Println(strings.IndexFunc(str, unicode.IsPunct))
    fmt.Println(strings.IndexFunc(str, unicode.IsLetter))
    fmt.Println(strings.IndexFunc(str, unicode.IsSpace))
    fmt.Println(strings.IndexFunc(str, unicode.IsUpper))
}

Funções Join e Fields

Função Join

func Join(elems []string, sep string) string

Join une os elementos de elems em uma única string, separados por sep. Por exemplo, se você tiver uma slice de strings ["Alberto", "Santos", "Dumont"] e quiser uni-las em uma string única separada por underscores, você usaria Join.

Função Fields

func Fields(s string) []string

Fields divide a string s em uma slice de strings, separando por espaços. É o inverso da função Join quando o separador é um espaço.

Um exemplo de uso de Join e Fields:

package main

import (
	"fmt"
	"strings"
)

func main() {
	nome := "Alberto Santos Dumont"

	split := strings.Fields(nome)

	fmt.Println(split)

	join := strings.Join(split, "_")

	fmt.Println(join)
}

Funções LastIndex, LastIndexAny, LastIndexByte e LastIndexFunc

O pacote strings também oferece funções que operam de maneira semelhante às funções Index..., mas procuram a última ocorrência de uma sub-string ou caractere em uma string principal.

Função LastIndex

func LastIndex(s, ss string) int

LastIndex retorna o índice da última ocorrência da sub-string ss dentro da string s. Se ss não for encontrada, a função retorna -1. Por exemplo:

...
    str := "Pop!_OS is an operating system..."
    fmt.Println(strings.LastIndex(str, "op")) // Retorna o índice da última ocorrência de "op"

Função LastIndexFunc

func LastIndexFunc(s string, f func(rune) bool) int

LastIndexFunc retorna o índice do último caractere em s que satisfaz a função f. Se nenhum caractere satisfizer f, retorna -1. f aceita um rune e retorna um bool.

Um exemplo de uso de LastIndexFunc com funções unicode.Is...:

package main

import (
	"fmt"
	"strings"
	"unicode"
)

func printArrow(r int) {
	fmt.Printf("%s>\n", strings.Repeat("-", r-1))
}

func main() {
	str := "The American Revolution, or American Revolution of 1776, had its roots"

	fmt.Println(str)
	printArrow(strings.LastIndexFunc(str, unicode.IsNumber)) // Índice do último número
	printArrow(strings.LastIndexFunc(str, unicode.IsPunct))  // Índice do último caractere de pontuação
	printArrow(strings.LastIndexFunc(str, unicode.IsLetter)) // Índice da última letra
	printArrow(strings.LastIndexFunc(str, unicode.IsSpace))  // Índice do último espaço
	printArrow(strings.LastIndexFunc(str, unicode.IsUpper))  // Índice da última letra maiúscula
}

Os índices retornados são usados pela função printArrow para desenhar uma seta até a posição do caractere encontrado. Veja o resultado abaixo:

The American Revolution, or American Revolution of 1776, had its roots
----------------------------------------------------->
------------------------------------------------------>
-------------------------------------------------------------------->
--------------------------------------------------------------->
------------------------------------>

Função Repeat

A função Repeat é utilizada para criar uma nova string consistindo de múltiplas cópias de uma string original.

Assinatura da Função

func Repeat(s string, count int) string

Repeat recebe uma string s e um número inteiro count, retornando uma nova string que consiste na string s repetida count vezes. Se count for negativo ou zero, a função retorna uma string vazia.

...
    fmt.Print(strings.Repeat("ha ", 3))  // imprime "ha ha ha "

Função Replace e ReplaceAll

As funções Replace e ReplaceAll são utilizadas para substituir ocorrências de uma sub-string dentro de uma string principal.

Assinatura das Funções

func Replace(s, old, new string, n int) string
func ReplaceAll(s, old, new string) string

Função Replace

Replace retorna uma nova string baseada na string s, substituindo as primeiras n ocorrências da string old pela string new. Se n for -1, todas as ocorrências serão substituídas.

Função ReplaceAll

ReplaceAll é uma variação da função Replace onde todas as ocorrências da string old são substituídas pela string new, independentemente do número de ocorrências.

Exemplo de Uso

O exemplo a seguir demonstra como usar as funções Replace e ReplaceAll para substituir sub-strings em uma string principal:

package main

import (
    "fmt"
    "strings"
)

func main() {
    str := "A Revolução Americana, ou Revolução Americana de 1776, teve suas raízes"

    fmt.Println(strings.Replace(str, "Americana", "___________", 2))
    fmt.Println(strings.Replace(str, "Americana", "___________", -1))
    fmt.Println(strings.ReplaceAll(str, "Americana", "___________"))
}

As três chamadas às funções Replace e ReplaceAll, linhas 11 a 13, produzirão o mesmo resultado, substituindo todas as ocorrências de “Americana” por “_“:

A Revolução ___________, ou Revolução ___________ de 1776, teve suas raízes
A Revolução ___________, ou Revolução ___________ de 1776, teve suas raízes
A Revolução ___________, ou Revolução ___________ de 1776, teve suas raízes

Funções Split, SplitN, SplitAfter e SplitAfterN

O pacote strings oferece funções para dividir uma string em uma slice de strings com base em um separador especificado.

Assinatura das Funções

func Split(s, sep string) []string
func SplitN(s, sep string, n int) []string
func SplitAfter(s, sep string) []string
func SplitAfterN(s, sep string, n int) []string

Funcionamento das Funções

  • Split: Divide a string s em todos os pontos onde o separador sep ocorre.
  • SplitN: Semelhante a Split, mas divide a string s em no máximo n substrings.
  • SplitAfter: Divide a string s em todos os pontos logo após o separador sep, mantendo o separador como parte da substring precedente.
  • SplitAfterN: Semelhante a SplitAfter, mas divide a string s em no máximo n substrings.

Exemplo de Uso

O exemplo a seguir demonstra como usar as funções Split, SplitN, SplitAfter e SplitAfterN para dividir uma string:

package main

import (
    "fmt"
    "strings"
)

func main() {
    str := "a,b,c,d"

    // Divide a string em todas as ocorrências do separador
    fmt.Printf("      Split: %q\n", strings.Split(str, ","))
    
    // Divide a string em no máximo n substrings
    fmt.Printf("     SplitN: %q\n", strings.SplitN(str, ",", 2))
    
    // Divide a string em todas as ocorrências do separador, mantendo o separador com a substring anterior
    fmt.Printf(" SplitAfter: %q\n", strings.SplitAfter(str, ","))
    
    // Divide a string em no máximo n substrings, mantendo o separador com a substring anterior
    fmt.Printf("SplitAfterN: %q\n", strings.SplitAfterN(str, ",", 2))
}

O retorno deste código será:

      Split: ["a" "b" "c" "d"]
     SplitN: ["a" "b,c,d"]
 SplitAfter: ["a," "b," "c," "d"]
SplitAfterN: ["a," "b,c,d"]

Note que as funções SplitAfter e SplitAfterN mantêm o separador, neste caso a vírgula, e o fatiamento é feito logo após o separador, como indicado pelo after no nome da função.

Funções de Formatação Title e alguns To…

O pacote strings fornece funções para alterar a formatação de strings em termos de caixa alta e baixa.

Funções Title, ToTitle, ToUpper e ToLower

func Title(s string) string
func ToTitle(s string) string
func ToUpper(s string) string
func ToLower(s string) string
  • Title converte a primeira letra de cada palavra em maiúscula.
  • ToTitle converte todas as letras em maiúsculas, semelhante a ToUpper.
  • ToUpper converte todas as letras da string em maiúsculas.
  • ToLower converte todas as letras da string em minúsculas.

Exemplo de Uso

O exemplo a seguir demonstra como usar as funções Title, ToTitle, ToUpper, e ToLower:

package main

import (
    "fmt"
    "strings"
)

func main() {
    str := "prIncíPios básICos do paSTafArismo"

    fmt.Println(strings.Title(str))
    fmt.Println(strings.ToTitle(str))
    fmt.Println(strings.ToUpper(str))
    fmt.Println(strings.ToLower(str))
    fmt.Println(strings.Title(strings.ToLower(str)))
}

O código acima produzirá a saída:

PrIncíPios BásICos Do PaSTafArismo
PRINCÍPIOS BÁSICOS DO PASTAFARISMO
PRINCÍPIOS BÁSICOS DO PASTAFARISMO
princípios básicos do pastafarismo
Princípios Básicos Do Pastafarismo

Funções Trim…

O pacote strings oferece diversas funções Trim... para remover caracteres específicos do início e/ou do final de uma string.

Assinatura das Funções Trim…

func Trim(s, cutset string) string
func TrimFunc(s string, f func(rune) bool) string
func TrimLeft(s, cutset string) string
func TrimLeftFunc(s string, f func(rune) bool) string
func TrimPrefix(s, prefix string) string
func TrimRight(s, cutset string) string
func TrimRightFunc(s string, f func(rune) bool) string
func TrimSpace(s string) string
func TrimSuffix(s, suffix string) string
  • Trim remove caracteres especificados por cutset do início e do final de s.
  • TrimFunc usa uma função de filtro para determinar quais caracteres remover.
  • TrimLeft e TrimRight removem caracteres do início ou do final de s, respectivamente.
  • TrimPrefix e TrimSuffix removem um prefixo ou um sufixo específico de s.
  • TrimSpace remove espaços em branco do início e do final de s.

Exemplo de Uso

O exemplo a seguir ilustra o uso de várias funções Trim...:

package main

import (
	"fmt"
	"strings"
	"unicode"
)

func removeSelection(r rune) bool {
	if unicode.IsNumber(r) || r == ' ' || r == 'o' {
		return true
	}
	return false
}

func main() {
	var (
		str1 = "---Mais sem graça que a top-model ..."
		str2 = "  Mas ontem eu recebi um telegrama   "
		str3 = "o Prêmio Nobel de Física de 1921"
	)

	fmt.Printf("%q\n", strings.Trim(str1, "- ."))
	fmt.Printf("%q\n", strings.TrimLeft(str1, "- ."))
	fmt.Printf("%q\n", strings.TrimRight(str1, "- ."))
	fmt.Printf("%q\n", strings.TrimPrefix(str1, "-"))
	fmt.Printf("%q\n", strings.TrimSuffix(str1, "."))
	fmt.Printf("%q\n", strings.TrimSpace(str2))
	fmt.Printf("%q\n", strings.TrimRightFunc(str3, unicode.IsNumber))
	fmt.Printf("%q\n", strings.TrimFunc(str3, removeSelection))
}

O código acima produzirá a saída:

"Mais sem graça que a top-model"
"Mais sem graça que a top-model ..."
"---Mais sem graça que a top-model"
"--Mais sem graça que a top-model ..."
"---Mais sem graça que a top-model .."
"Mas ontem eu recebi um telegrama"
"o Prêmio Nobel de Física de "
"Prêmio Nobel de Física de"

Considerações Finais

Ao longo deste artigo, exploramos uma variedade de funções fundamentais dos pacotes fmt e strings do GoLang, mergulhando nas nuances e capacidades que cada função oferece. A jornada pelas diversas funcionalidades, desde formatação de strings e operações de entrada/saída até manipulações complexas de texto, demonstrou a versatilidade e o poder que essas bibliotecas padrão colocam à disposição dos desenvolvedores.

A discussão detalhada sobre cada função não foi apenas uma revisão, mas também uma oportunidade de reconhecer a evolução constante do GoLang e as práticas recomendadas para seu uso eficaz. A familiaridade com essas funções é vital, pois elas constituem a base sobre a qual operações mais complexas são construídas e soluções inovadoras são desenvolvidas.

No próximo artigo, planejo expandir nosso horizonte, explorando outros pacotes cruciais da biblioteca padrão do GoLang. O objetivo é aprofundar ainda mais nosso conhecimento e compreensão do ecossistema GoLang, abordando pacotes que são essenciais para o desenvolvimento robusto e eficiente de aplicações.

Deixe um comentário

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.