std.mem.eql, indexOf e comparações em Zig — Referência e Exemplos

std.mem.eql, indexOf e Comparações

As funções de comparação e busca de std.mem são essenciais para trabalhar com strings e slices em Zig. Como o Zig trata strings como []const u8, essas funções substituem operadores de igualdade e métodos de string de outras linguagens.

Visão Geral

Em Zig, o operador == não funciona para comparar slices (ele compara os ponteiros, não o conteúdo). Para comparar conteúdo, use std.mem.eql:

const std = @import("std");
const mem = std.mem;

// CORRETO: compara conteúdo
if (mem.eql(u8, str1, str2)) { ... }

// INCORRETO: compara ponteiros, não conteúdo
// if (str1 == str2) { ... }

Funções de Igualdade

mem.eql

pub fn eql(comptime T: type, a: []const T, b: []const T) bool

Compara dois slices elemento por elemento. Retorna true se tiverem o mesmo comprimento e conteúdo.

mem.order

pub fn order(comptime T: type, lhs: []const T, rhs: []const T) std.math.Order

Compara lexicograficamente. Retorna .lt, .eq ou .gt.

mem.lessThan

pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) bool

Retorna true se lhs for lexicograficamente menor que rhs.

Funções de Busca

mem.indexOf

pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize

Encontra a primeira ocorrência de needle em haystack. Retorna null se não encontrar.

mem.lastIndexOf

pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize

Encontra a última ocorrência.

mem.indexOfScalar

pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize

Encontra a primeira ocorrência de um único valor.

mem.indexOfAny

pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize

Encontra a primeira ocorrência de qualquer valor do conjunto.

mem.count

pub fn count(comptime T: type, haystack: []const T, needle: []const T) usize

Conta ocorrências não sobrepostas de needle em haystack.

Funções de Prefixo e Sufixo

mem.startsWith

pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool

Verifica se haystack começa com needle.

mem.endsWith

pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool

Verifica se haystack termina com needle.

Exemplo 1: Processador de Comandos

const std = @import("std");
const mem = std.mem;

const Comando = enum {
    ajuda,
    listar,
    sair,
    desconhecido,
};

fn interpretarComando(entrada: []const u8) Comando {
    const cmd = mem.trim(u8, entrada, " \t\n\r");

    if (mem.eql(u8, cmd, "ajuda") or mem.eql(u8, cmd, "help")) {
        return .ajuda;
    } else if (mem.eql(u8, cmd, "listar") or mem.eql(u8, cmd, "ls")) {
        return .listar;
    } else if (mem.eql(u8, cmd, "sair") or mem.eql(u8, cmd, "exit")) {
        return .sair;
    } else {
        return .desconhecido;
    }
}

pub fn main() void {
    const comandos = [_][]const u8{ "ajuda", "  listar  ", "sair", "foo" };

    for (comandos) |cmd| {
        const resultado = interpretarComando(cmd);
        std.debug.print("'{s}' -> {}\n", .{ mem.trim(u8, cmd, " "), resultado });
    }
}

Exemplo 2: Busca e Extração de Texto

const std = @import("std");
const mem = std.mem;

fn extrairValorTag(html: []const u8, tag: []const u8) ?[]const u8 {
    // Buscar tag de abertura
    var buf_abertura: [64]u8 = undefined;
    const abertura = std.fmt.bufPrint(&buf_abertura, "<{s}>", .{tag}) catch return null;

    var buf_fechamento: [64]u8 = undefined;
    const fechamento = std.fmt.bufPrint(&buf_fechamento, "</{s}>", .{tag}) catch return null;

    const inicio = (mem.indexOf(u8, html, abertura) orelse return null) + abertura.len;
    const fim = mem.indexOf(u8, html[inicio..], fechamento) orelse return null;

    return html[inicio..][0..fim];
}

pub fn main() void {
    const html = "<div><titulo>Meu Site</titulo><corpo>Conteúdo</corpo></div>";

    if (extrairValorTag(html, "titulo")) |valor| {
        std.debug.print("Título: {s}\n", .{valor}); // "Meu Site"
    }

    if (extrairValorTag(html, "corpo")) |valor| {
        std.debug.print("Corpo: {s}\n", .{valor}); // "Conteúdo"
    }

    if (extrairValorTag(html, "autor")) |_| {
        std.debug.print("Autor encontrado\n", .{});
    } else {
        std.debug.print("Tag 'autor' não encontrada\n", .{});
    }
}

Exemplo 3: Validação de Formato

const std = @import("std");
const mem = std.mem;

fn validarEmail(email: []const u8) bool {
    // Verificações básicas
    if (email.len < 5) return false;

    // Deve conter exatamente um '@'
    if (mem.count(u8, email, "@") != 1) return false;

    const pos_arroba = mem.indexOfScalar(u8, email, '@').?;

    // Deve ter algo antes e depois do @
    if (pos_arroba == 0 or pos_arroba == email.len - 1) return false;

    // Domínio deve conter pelo menos um ponto
    const dominio = email[pos_arroba + 1 ..];
    if (mem.indexOfScalar(u8, dominio, '.') == null) return false;

    // Não pode começar ou terminar com ponto
    if (mem.startsWith(u8, email, ".") or mem.endsWith(u8, email, ".")) return false;

    return true;
}

pub fn main() void {
    const emails = [_][]const u8{
        "usuario@exemplo.com",
        "invalido",
        "@sem-usuario.com",
        "sem-dominio@",
        "dois@@arrobas.com",
        "ok@dominio.br",
    };

    for (emails) |email| {
        const valido = if (validarEmail(email)) "valido" else "invalido";
        std.debug.print("{s:<25} -> {s}\n", .{ email, valido });
    }
}

Padrões Comuns

Comparação em Switch

O Zig não permite switch em slices diretamente. Use uma cadeia de if:

fn processarExtensao(ext: []const u8) []const u8 {
    if (mem.eql(u8, ext, ".zig")) return "Zig";
    if (mem.eql(u8, ext, ".rs")) return "Rust";
    if (mem.eql(u8, ext, ".go")) return "Go";
    return "Desconhecido";
}

Busca com Contexto

fn encontrarTodos(texto: []const u8, padrao: []const u8) void {
    var pos: usize = 0;
    while (mem.indexOf(u8, texto[pos..], padrao)) |offset| {
        const abs_pos = pos + offset;
        std.debug.print("Encontrado na posição {d}\n", .{abs_pos});
        pos = abs_pos + padrao.len;
    }
}

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

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