Cheatsheet: Strings em Zig

Cheatsheet: Strings em Zig

Em Zig, strings são simplesmente slices de bytes ([]const u8). Não existe um tipo String especial. Esta cheatsheet cobre todas as operações comuns com strings.

Tipos de String

// String literal — array de bytes com sentinela null
const literal: *const [5:0]u8 = "Hello";

// Slice de string (mais comum)
const slice: []const u8 = "Hello";

// String mutável
var buffer: [100]u8 = undefined;
var str: []u8 = buffer[0..5];

// String com sentinela (compatível com C)
const c_str: [*:0]const u8 = "Hello";
const sentinel_slice: [:0]const u8 = "Hello";

Comparação de Strings

const std = @import("std");

const a = "hello";
const b = "hello";
const c = "world";

// Comparar igualdade
const iguais = std.mem.eql(u8, a, b);     // true
const diferentes = std.mem.eql(u8, a, c);  // false

// Comparação ordenada
const ordem = std.mem.order(u8, a, c);  // .lt, .eq ou .gt
const menor = std.mem.lessThan(u8, a, c);  // true ("hello" < "world")

Busca em Strings

const texto = "Hello, World! Hello, Zig!";

// Encontrar substring
const pos = std.mem.indexOf(u8, texto, "World");  // ?usize = 7
const ultima = std.mem.lastIndexOf(u8, texto, "Hello");  // ?usize = 14

// Encontrar caractere
const virgula = std.mem.indexOfScalar(u8, texto, ',');  // ?usize = 5

// Verificar prefixo e sufixo
const comeca = std.mem.startsWith(u8, texto, "Hello");  // true
const termina = std.mem.endsWith(u8, texto, "Zig!");    // true

// Contar ocorrências
const count = std.mem.count(u8, texto, "Hello");  // 2

// Verificar se contém
const contem = std.mem.indexOf(u8, texto, "World") != null;  // true

Fatiamento (Slicing)

const texto = "Hello, World!";

const hello = texto[0..5];     // "Hello"
const world = texto[7..12];    // "World"
const resto = texto[7..];      // "World!"

// Obter último caractere
const ultimo = texto[texto.len - 1];  // '!'

// Iterar sobre caracteres
for (texto) |byte| {
    std.debug.print("{c}", .{byte});
}

// Iterar com índice
for (texto, 0..) |byte, i| {
    std.debug.print("[{}]={c} ", .{ i, byte });
}

Divisão (Split)

const std = @import("std");

const csv = "nome,idade,cidade";

// Split por delimitador
var it = std.mem.splitSequence(u8, csv, ",");
while (it.next()) |campo| {
    std.debug.print("Campo: {s}\n", .{campo});
}
// Saída: "nome", "idade", "cidade"

// Split por caractere único
const path = "/usr/local/bin";
var it2 = std.mem.splitScalar(u8, path, '/');
while (it2.next()) |parte| {
    if (parte.len > 0) {
        std.debug.print("Parte: {s}\n", .{parte});
    }
}

// Tokenize (ignora delimitadores consecutivos)
const texto = "  hello   world  ";
var tok = std.mem.tokenizeScalar(u8, texto, ' ');
while (tok.next()) |token| {
    std.debug.print("Token: '{s}'\n", .{token});
}
// Saída: "hello", "world"

Concatenação

const std = @import("std");

// Em comptime (concatenação de literais)
const saudacao = "Olá, " ++ "mundo!";  // "Olá, mundo!"

// Repetição em comptime
const tracos = "-" ** 20;  // "--------------------"

// Em runtime com allocator
const allocator = std.heap.page_allocator;
const resultado = try std.mem.concat(allocator, u8, &.{ "Hello", " ", "World" });
defer allocator.free(resultado);

// Com std.fmt.allocPrint
const nome = "Zig";
const msg = try std.fmt.allocPrint(allocator, "Olá, {s}! Versão {d}", .{ nome, 13 });
defer allocator.free(msg);

Formatação

const std = @import("std");

// Formatar em buffer fixo
var buf: [256]u8 = undefined;
const resultado = try std.fmt.bufPrint(&buf, "Valor: {d}, Hex: 0x{x}", .{ 42, 255 });
// resultado é []u8 contendo "Valor: 42, Hex: 0xff"

// Especificadores comuns
// {s}     — string ([]const u8)
// {d}     — decimal
// {x}     — hexadecimal minúsculo
// {X}     — hexadecimal maiúsculo
// {b}     — binário
// {o}     — octal
// {e}     — notação científica
// {c}     — caractere (u8)
// {any}   — qualquer tipo (debug)
// {}      — formato padrão

// Preenchimento e alinhamento
const alinhado = try std.fmt.bufPrint(&buf, "|{s:>10}|", .{"zig"});
// "|       zig|"

const esquerda = try std.fmt.bufPrint(&buf, "|{s:<10}|", .{"zig"});
// "|zig       |"

const centro = try std.fmt.bufPrint(&buf, "|{s:^10}|", .{"zig"});
// "|   zig    |"

// Zeros à esquerda
const zeros = try std.fmt.bufPrint(&buf, "{d:0>5}", .{42});
// "00042"

Trim (Remover Espaços)

const std = @import("std");

const texto = "  Hello, World!  ";

// Trim ambos os lados
const trimmed = std.mem.trim(u8, texto, " ");  // "Hello, World!"

// Trim à esquerda
const ltrimmed = std.mem.trimLeft(u8, texto, " ");  // "Hello, World!  "

// Trim à direita
const rtrimmed = std.mem.trimRight(u8, texto, " ");  // "  Hello, World!"

// Trim de múltiplos caracteres
const dados = "\n\t  dados  \n\t";
const limpo = std.mem.trim(u8, dados, &[_]u8{ ' ', '\n', '\t' });  // "dados"

Substituição

const std = @import("std");
const allocator = std.heap.page_allocator;

const texto = "Hello World Hello Zig";

// Substituir todas as ocorrências
const resultado = try std.mem.replaceOwned(u8, allocator, texto, "Hello", "Olá");
defer allocator.free(resultado);
// "Olá World Olá Zig"

Conversão Maiúsculas/Minúsculas

const std = @import("std");

const texto = "Hello World";
var buf: [100]u8 = undefined;

// Para minúsculas
const lower = std.ascii.lowerString(buf[0..texto.len], texto);
// "hello world"

// Para maiúsculas
const upper = std.ascii.upperString(buf[0..texto.len], texto);
// "HELLO WORLD"

// Verificar se caractere é letra, dígito, etc.
const eh_alpha = std.ascii.isAlphabetic('A');  // true
const eh_digit = std.ascii.isDigit('5');       // true
const eh_space = std.ascii.isWhitespace(' ');  // true

Conversão Número ↔ String

const std = @import("std");

// String → Inteiro
const num = try std.fmt.parseInt(i32, "42", 10);    // 42
const hex = try std.fmt.parseInt(u32, "FF", 16);     // 255
const bin = try std.fmt.parseInt(u8, "1010", 2);     // 10

// String → Float
const pi = try std.fmt.parseFloat(f64, "3.14159");  // 3.14159

// Inteiro → String
var buf: [20]u8 = undefined;
const str = try std.fmt.bufPrint(&buf, "{d}", .{42});  // "42"

ArrayList como String Builder

const std = @import("std");

pub fn construirString(allocator: std.mem.Allocator) ![]u8 {
    var lista = std.ArrayList(u8).init(allocator);
    defer lista.deinit();

    try lista.appendSlice("Olá");
    try lista.appendSlice(", ");
    try lista.appendSlice("mundo!");
    try lista.append('!');

    // Transferir propriedade para o chamador
    return lista.toOwnedSlice();
}

UTF-8

const std = @import("std");

const texto = "Olá, São Paulo!";

// Zig trata strings como bytes UTF-8
// Para iterar sobre code points Unicode:
var view = std.unicode.Utf8View.initUnchecked(texto);
var it = view.iterator();
while (it.nextCodepoint()) |cp| {
    std.debug.print("U+{X:0>4}\n", .{cp});
}

// Validar UTF-8
const valido = std.unicode.utf8ValidateSlice(texto);  // true

// Comprimento em code points (não em bytes)
const byte_len = texto.len;  // número de bytes
var cp_len: usize = 0;
var iter = std.unicode.Utf8View.initUnchecked(texto).iterator();
while (iter.nextCodepoint()) |_| {
    cp_len += 1;
}

Tabela de Referência Rápida

OperaçãoFunção
Compararstd.mem.eql(u8, a, b)
Buscar substringstd.mem.indexOf(u8, str, sub)
Começa comstd.mem.startsWith(u8, str, prefix)
Termina comstd.mem.endsWith(u8, str, suffix)
Dividirstd.mem.splitSequence(u8, str, delim)
Trimstd.mem.trim(u8, str, chars)
Concatenarstd.mem.concat(alloc, u8, slices)
Formatarstd.fmt.bufPrint(&buf, fmt, args)
Parse intstd.fmt.parseInt(T, str, base)
Parse floatstd.fmt.parseFloat(T, str)
Minúsculasstd.ascii.lowerString(buf, str)

Veja Também

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.