Golang – 06. Biblioteca Padrão I – fmt e strings
- Golang – 01. Introdução
- Golang – 02. Tipos Básicos
- Golang – 03. Structs e Funções e Métodos
- Golang – 04. Estruturas de Controle
- Golang – 05. Gerenciando Pacotes
- Golang – 06. Biblioteca Padrão I – fmt e strings
- Golang – 07. Biblioteca Padrão II – os, os/exec e os/user
- Golang – 08. Interface
- Golang – 09. Goroutines – Concorrência e Paralelismo
- Golang – 10. Goroutines – Canais
- Golang – 11. Pacotes e Documentação no Go
Índice
- 1. Pacote fmt
- 1.1. Códigos de Formatação
- 1.2. Funções Print, Printf e Println
- 1.2.1. Retorno das Funções Print
- 1.3. Funções Scan, Scanf e Scanln
- 1.3.1. Separadores Espaço e Quebra de Linha
- 1.3.2. Retorno das Funções Scan
- 1.4. Funções Sprint, Sprintln e Sprintf
- 1.5. Função Errorf
- 1.6. Como ler Strings com espaços no fmt?
- 2. Pacote Strings
- 2.1. Função strings.Compare
- 2.2. Funções Contains, ContainsAny e ContainsRune
- 2.2.1. Função Contains
- 2.2.2. Função ContainsAny
- 2.2.3. Função ContainsRune
- 2.3. Função Count
- 2.4. Função Cut
- 2.5. Funções Index, IndexAny, IndexByte e IndexRune
- 2.5.1. Função Index
- 2.5.2. Função IndexAny
- 2.5.3. Função IndexByte
- 2.5.4. Função IndexRune
- 2.6. IndexFunc e as funções unicode.Is…
- 2.7. Funções Join e Fields
- 2.7.1. Função Join
- 2.7.2. Função Fields
- 2.8. Funções LastIndex, LastIndexAny, LastIndexByte e LastIndexFunc
- 2.8.1. Função LastIndex
- 2.8.2. Função LastIndexFunc
- 2.9. Função Repeat
- 2.10. Função Replace e ReplaceAll
- 2.10.1. Assinatura das Funções
- 2.10.2. Função Replace
- 2.10.3. Função ReplaceAll
- 2.10.4. Exemplo de Uso
- 2.11. Funções Split, SplitN, SplitAfter e SplitAfterN
- 2.11.1. Assinatura das Funções
- 2.11.2. Funcionamento das Funções
- 2.11.3. Exemplo de Uso
- 2.12. Funções de Formatação Title e alguns To…
- 2.12.1. Funções Title, ToTitle, ToUpper e ToLower
- 2.12.2. Exemplo de Uso
- 2.13. Funções Trim…
- 2.13.1. Assinatura das Funções Trim…
- 2.13.2. Exemplo de Uso
- 3. Considerações Finais
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ódigo | Descrição |
|---|---|
| %% | caractere porcentagem (%) |
| %v | formatação padrão para o tipo passado |
| %T | imprime o tipo passado do valor passado |
| %s | string |
| %f | decimal de ponto flutuante |
| %e ou %E | notação científica |
| %q | string entre duplas aspas |
| %c | o caractere representado pelo Unicode |
| %d | inteiro decimal (base 10) |
| %o e %O | base 8 e base 8 com prefixo “0o” |
| %x e %X | base 16 e base 16 com a-f capitalizado |
| %t | booleano (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:
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á:
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:
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:
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")) // 1Funçõ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", "")) // trueUma 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")) // trueFunçã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)) // trueNeste 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")) // 3A 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")) // 4Funçã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")) // 2Funçã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')) // 3Funçã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')) // 4IndexFunc 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ção | Assinatura | True se rune é? |
|---|---|---|
| IsControl | func IsControl(r rune) bool | caractere de controle |
| IsDigit | func IsDigit(r rune) bool | decimal |
| IsGraphic | func IsGraphic(r rune) bool | caractere gráfico |
| IsLetter | func IsLetter(r rune) bool | letra |
| IsLower | func IsLower(r rune) bool | caractere minúsculo |
| IsNumber | func IsNumber(r rune) bool | número |
| IsPunct | func IsPunct(r rune) bool | caractere de pontuação |
| IsSpace | func IsSpace(r rune) bool | espaço |
| IsPrint | func IsPrint(r rune) bool | imprimível (caracteres, letras, …) |
| IsSymbol | func IsSymbol(r rune) bool | símbolo |
| IsUpper | func IsUpper(r rune) bool | caractere maiúsculo |
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 stringsem todos os pontos onde o separadorsepocorre.SplitN: Semelhante aSplit, mas divide a stringsem no máximonsubstrings.SplitAfter: Divide a stringsem todos os pontos logo após o separadorsep, mantendo o separador como parte da substring precedente.SplitAfterN: Semelhante aSplitAfter, mas divide a stringsem no máximonsubstrings.
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
Titleconverte a primeira letra de cada palavra em maiúscula.ToTitleconverte todas as letras em maiúsculas, semelhante aToUpper.ToUpperconverte todas as letras da string em maiúsculas.ToLowerconverte 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
Trimremove caracteres especificados porcutsetdo início e do final des.TrimFuncusa uma função de filtro para determinar quais caracteres remover.TrimLefteTrimRightremovem caracteres do início ou do final des, respectivamente.TrimPrefixeTrimSuffixremovem um prefixo ou um sufixo específico des.TrimSpaceremove espaços em branco do início e do final des.
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 uma resposta