Como Buscar Substrings em Zig
Encontrar um trecho de texto dentro de uma string é uma tarefa comum em processamento de texto, validação de dados e parsing. Zig oferece funções eficientes na biblioteca padrão para busca de substrings.
Busca Básica com indexOf
A função std.mem.indexOf retorna a posição da primeira ocorrência de uma substring, ou null se não for encontrada.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const texto = "A linguagem Zig é moderna e eficiente";
// Buscar substring
if (std.mem.indexOf(u8, texto, "Zig")) |pos| {
try stdout.print("\"Zig\" encontrado na posição {d}\n", .{pos});
} else {
try stdout.print("\"Zig\" não encontrado\n", .{});
}
// Buscar substring inexistente
if (std.mem.indexOf(u8, texto, "Rust")) |pos| {
try stdout.print("\"Rust\" encontrado na posição {d}\n", .{pos});
} else {
try stdout.print("\"Rust\" não encontrado\n", .{});
}
// Buscar caractere único com indexOfScalar
if (std.mem.indexOfScalar(u8, texto, 'Z')) |pos| {
try stdout.print("'Z' encontrado na posição {d}\n", .{pos});
}
}
Saída esperada:
"Zig" encontrado na posição 12
"Rust" não encontrado
'Z' encontrado na posição 12
Buscar Última Ocorrência
Use std.mem.lastIndexOf para encontrar a última ocorrência de uma substring.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const caminho = "/home/usuario/documentos/projeto/arquivo.zig";
// Encontrar última barra
if (std.mem.lastIndexOfScalar(u8, caminho, '/')) |pos| {
const diretorio = caminho[0..pos];
const arquivo = caminho[pos + 1 ..];
try stdout.print("Diretório: {s}\n", .{diretorio});
try stdout.print("Arquivo: {s}\n", .{arquivo});
}
// Encontrar última ocorrência de extensão
const nome_arquivo = "relatorio.backup.2026.tar.gz";
if (std.mem.lastIndexOfScalar(u8, nome_arquivo, '.')) |pos| {
const extensao = nome_arquivo[pos..];
try stdout.print("Extensão: {s}\n", .{extensao});
}
}
Saída esperada:
Diretório: /home/usuario/documentos/projeto
Arquivo: arquivo.zig
Extensão: .gz
Verificar se Contém (Contains)
Crie uma função simples para verificar se uma string contém outra.
const std = @import("std");
fn contem(texto: []const u8, busca: []const u8) bool {
return std.mem.indexOf(u8, texto, busca) != null;
}
fn contemIgnorandoCaso(allocator: std.mem.Allocator, texto: []const u8, busca: []const u8) !bool {
const texto_lower = try std.ascii.allocLowerString(allocator, texto);
defer allocator.free(texto_lower);
const busca_lower = try std.ascii.allocLowerString(allocator, busca);
defer allocator.free(busca_lower);
return std.mem.indexOf(u8, texto_lower, busca_lower) != null;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const texto = "Programação em Zig é divertida";
try stdout.print("Contém \"Zig\": {}\n", .{contem(texto, "Zig")});
try stdout.print("Contém \"Python\": {}\n", .{contem(texto, "Python")});
// Case-insensitive
const resultado = try contemIgnorandoCaso(allocator, texto, "zig");
try stdout.print("Contém \"zig\" (case-insensitive): {}\n", .{resultado});
}
Saída esperada:
Contém "Zig": true
Contém "Python": false
Contém "zig" (case-insensitive): true
Contar Ocorrências
Conte quantas vezes uma substring aparece no texto.
const std = @import("std");
fn contarOcorrencias(texto: []const u8, busca: []const u8) usize {
var contador: usize = 0;
var pos: usize = 0;
while (pos <= texto.len - busca.len) {
if (std.mem.indexOf(u8, texto[pos..], busca)) |encontrado| {
contador += 1;
pos += encontrado + busca.len;
} else {
break;
}
}
return contador;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const texto = "abracadabra";
try stdout.print("Ocorrências de \"abra\" em \"abracadabra\": {d}\n", .{contarOcorrencias(texto, "abra")});
try stdout.print("Ocorrências de \"a\" em \"abracadabra\": {d}\n", .{contarOcorrencias(texto, "a")});
const frase = "o rato roeu a roupa do rei de roma";
try stdout.print("Ocorrências de \"r\" em frase: {d}\n", .{contarOcorrencias(frase, "r")});
try stdout.print("Ocorrências de \"ro\" em frase: {d}\n", .{contarOcorrencias(frase, "ro")});
}
Saída esperada:
Ocorrências de "abra" em "abracadabra": 2
Ocorrências de "a" em "abracadabra": 5
Ocorrências de "r" em frase: 5
Ocorrências de "ro" em frase: 3
Encontrar Todas as Posições
Retorne todas as posições onde uma substring ocorre.
const std = @import("std");
fn encontrarTodas(allocator: std.mem.Allocator, texto: []const u8, busca: []const u8) ![]usize {
var posicoes = std.ArrayList(usize).init(allocator);
var pos: usize = 0;
while (pos <= texto.len - busca.len) {
if (std.mem.indexOf(u8, texto[pos..], busca)) |encontrado| {
try posicoes.append(pos + encontrado);
pos += encontrado + 1;
} else {
break;
}
}
return posicoes.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 = "Zig é legal. Zig é rápido. Zig é seguro.";
const posicoes = try encontrarTodas(allocator, texto, "Zig");
defer allocator.free(posicoes);
try stdout.print("\"Zig\" encontrado em {d} posições: ", .{posicoes.len});
for (posicoes, 0..) |pos, i| {
if (i > 0) try stdout.print(", ", .{});
try stdout.print("{d}", .{pos});
}
try stdout.print("\n", .{});
}
Saída esperada:
"Zig" encontrado em 3 posições: 0, 14, 28
Buscar com indexOfAny
Use std.mem.indexOfAny para encontrar qualquer caractere de um conjunto.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const texto = "nome.sobrenome@email.com";
// Encontrar primeiro caractere especial
if (std.mem.indexOfAny(u8, texto, ".@-_")) |pos| {
try stdout.print("Primeiro caractere especial na posição {d}: '{c}'\n", .{ pos, texto[pos] });
}
// Verificar se contém dígitos
const frase = "Olá Mundo 2026";
if (std.mem.indexOfAny(u8, frase, "0123456789")) |pos| {
try stdout.print("Primeiro dígito na posição {d}: '{c}'\n", .{ pos, frase[pos] });
}
}
Saída esperada:
Primeiro caractere especial na posição 4: '.'
Primeiro dígito na posição 10: '2'
Exemplo Prático: Validar Email Simples
const std = @import("std");
fn validarEmail(email: []const u8) bool {
// Deve conter exatamente um @
const arroba = std.mem.indexOf(u8, email, "@") orelse return false;
// @ não pode ser o primeiro ou último caractere
if (arroba == 0 or arroba == email.len - 1) return false;
// Deve ter pelo menos um ponto após o @
const dominio = email[arroba + 1 ..];
if (std.mem.indexOf(u8, dominio, ".") == null) return false;
// Domínio não pode terminar com ponto
if (std.mem.endsWith(u8, dominio, ".")) return false;
return true;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const emails = [_][]const u8{
"usuario@email.com",
"invalido",
"@sem-usuario.com",
"sem-dominio@",
"user@sem-ponto",
"ok@dominio.com.br",
};
for (emails) |email| {
const valido = validarEmail(email);
try stdout.print(" {s:<25} -> {s}\n", .{ email, if (valido) "Válido" else "Inválido" });
}
}
Saída esperada:
usuario@email.com -> Válido
invalido -> Inválido
@sem-usuario.com -> Inválido
sem-dominio@ -> Inválido
user@sem-ponto -> Inválido
ok@dominio.com.br -> Válido
Veja Também
- Comparar Strings — Compare strings por igualdade e ordem
- Dividir (Split) Strings — Divida texto por delimitador
- Substituir Texto em Strings — Substitua substrings encontradas
- Remover Espaços (Trim) — Limpe texto antes de buscar