Como Remover Espaços (Trim) de Strings em Zig

Como Remover Espaços (Trim) de Strings em Zig

Remover espaços em branco do início e/ou fim de strings é uma operação fundamental para limpeza de dados de entrada, parsing de arquivos e normalização de texto. Em Zig, as funções de trim trabalham com slices e não fazem alocação de memória.

Trim Básico com std.mem.trim

A função std.mem.trim remove caracteres específicos do início e do fim de um slice.

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Remover espaços em branco
    const texto = "   Olá Mundo   ";
    const limpo = std.mem.trim(u8, texto, " ");
    try stdout.print("Original: \"{s}\"\n", .{texto});
    try stdout.print("Trimmed:  \"{s}\"\n", .{limpo});

    // Remover tabs e espaços
    const com_tabs = "\t\t  Dados importantes  \t\n";
    const limpo2 = std.mem.trim(u8, com_tabs, " \t\n\r");
    try stdout.print("\nOriginal: \"{s}\"", .{com_tabs});
    try stdout.print("Trimmed:  \"{s}\"\n", .{limpo2});

    // Remover caracteres personalizados
    const com_barras = "///caminho/para/recurso///";
    const limpo3 = std.mem.trim(u8, com_barras, "/");
    try stdout.print("\nOriginal: \"{s}\"\n", .{com_barras});
    try stdout.print("Trimmed:  \"{s}\"\n", .{limpo3});
}

Saída esperada:

Original: "   Olá Mundo   "
Trimmed:  "Olá Mundo"

Original: "		  Dados importantes
"
Trimmed:  "Dados importantes"

Original: "///caminho/para/recurso///"
Trimmed:  "caminho/para/recurso"

Trim Apenas à Esquerda ou Direita

Use std.mem.trimLeft e std.mem.trimRight para remover caracteres de apenas um lado.

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    const texto = "   Olá Mundo   ";

    // Remover apenas do início
    const sem_esquerda = std.mem.trimLeft(u8, texto, " ");
    try stdout.print("trimLeft:  \"{s}\"\n", .{sem_esquerda});

    // Remover apenas do fim
    const sem_direita = std.mem.trimRight(u8, texto, " ");
    try stdout.print("trimRight: \"{s}\"\n", .{sem_direita});

    // Remover zeros à esquerda de um número
    const numero = "000042";
    const sem_zeros = std.mem.trimLeft(u8, numero, "0");
    try stdout.print("\nNúmero: \"{s}\" -> \"{s}\"\n", .{ numero, sem_zeros });

    // Remover nova linha do fim (comum ao ler arquivos)
    const linha = "conteúdo da linha\n";
    const sem_newline = std.mem.trimRight(u8, linha, "\n\r");
    try stdout.print("Linha: \"{s}\" -> \"{s}\"\n", .{ linha, sem_newline });
}

Saída esperada:

trimLeft:  "Olá Mundo   "
trimRight: "   Olá Mundo"

Número: "000042" -> "42"
Linha: "conteúdo da linha
" -> "conteúdo da linha"

Trim de Whitespace Completo

Defina uma constante com todos os caracteres de espaço em branco para uso recorrente.

const std = @import("std");

const WHITESPACE = " \t\n\r";

fn trimWhitespace(texto: []const u8) []const u8 {
    return std.mem.trim(u8, texto, WHITESPACE);
}

fn trimLeftWhitespace(texto: []const u8) []const u8 {
    return std.mem.trimLeft(u8, texto, WHITESPACE);
}

fn trimRightWhitespace(texto: []const u8) []const u8 {
    return std.mem.trimRight(u8, texto, WHITESPACE);
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    const entradas = [_][]const u8{
        "  normal  ",
        "\ttabulação\t",
        "\n\nnova linha\n\n",
        " \t\n misto \n\t ",
        "sem_espacos",
    };

    for (entradas) |entrada| {
        const limpo = trimWhitespace(entrada);
        try stdout.print("\"{s}\" -> \"{s}\" (len: {d} -> {d})\n", .{
            entrada, limpo, entrada.len, limpo.len,
        });
    }
}

Exemplo Prático: Processar Entrada de Usuário

Um exemplo comum é limpar dados de entrada antes de processá-los.

const std = @import("std");

const WHITESPACE = " \t\n\r";

const Campo = struct {
    chave: []const u8,
    valor: []const u8,
};

fn parseConfig(linha: []const u8) ?Campo {
    const limpa = std.mem.trim(u8, linha, WHITESPACE);
    if (limpa.len == 0) return null;

    // Ignorar comentários
    if (limpa[0] == '#') return null;

    // Dividir por '='
    const sep = std.mem.indexOf(u8, limpa, "=") orelse return null;

    return Campo{
        .chave = std.mem.trim(u8, limpa[0..sep], WHITESPACE),
        .valor = std.mem.trim(u8, limpa[sep + 1 ..], WHITESPACE),
    };
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    const config =
        \\# Configuração do servidor
        \\  host = localhost
        \\  porta = 8080
        \\
        \\  nome = Meu Servidor
        \\  debug = true
        \\# fim
    ;

    try stdout.print("Configurações parseadas:\n", .{});
    var linhas = std.mem.splitScalar(u8, config, '\n');
    while (linhas.next()) |linha| {
        if (parseConfig(linha)) |campo| {
            try stdout.print("  {s} = \"{s}\"\n", .{ campo.chave, campo.valor });
        }
    }
}

Saída esperada:

Configurações parseadas:
  host = "localhost"
  porta = "8080"
  nome = "Meu Servidor"
  debug = "true"

Normalizar Espaços Internos

Para normalizar espaços dentro de uma string (colapsar múltiplos espaços em um só), combine trim com tokenize.

const std = @import("std");

fn normalizarEspacos(allocator: std.mem.Allocator, texto: []const u8) ![]u8 {
    var tokens = std.mem.tokenizeScalar(u8, texto, ' ');
    var resultado = std.ArrayList(u8).init(allocator);
    defer resultado.deinit();

    var primeiro = true;
    while (tokens.next()) |token| {
        if (!primeiro) {
            try resultado.append(' ');
        }
        try resultado.appendSlice(token);
        primeiro = false;
    }

    return resultado.toOwnedSlice();
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const texto = "  Olá    Mundo   Zig    é   legal  ";
    const normalizado = try normalizarEspacos(allocator, texto);
    defer allocator.free(normalizado);

    try stdout.print("Original:    \"{s}\"\n", .{texto});
    try stdout.print("Normalizado: \"{s}\"\n", .{normalizado});
}

Saída esperada:

Original:    "  Olá    Mundo   Zig    é   legal  "
Normalizado: "Olá Mundo Zig é legal"

Referência Rápida

FunçãoDescrição
std.mem.trim(u8, str, chars)Remove chars de ambos os lados
std.mem.trimLeft(u8, str, chars)Remove chars do início
std.mem.trimRight(u8, str, chars)Remove chars do fim

Todas as funções retornam um sub-slice da string original, sem alocação de memória. O resultado aponta para a mesma memória que a string original.

Veja Também

Continue aprendendo Zig

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