Como Substituir Texto em Strings em Zig
Substituir trechos de texto dentro de strings é uma operação comum em processamento de dados, templates e sanitização de entrada. Em Zig, a substituição pode ser feita usando std.mem.replace ou com soluções manuais.
Substituição Básica com std.mem.replace
A função std.mem.replace substitui todas as ocorrências de um padrão em um buffer de saída.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const texto = "Olá Mundo! Olá Zig!";
// Substituir "Olá" por "Hello"
// O buffer de saída deve ter o mesmo tamanho ou maior
var buf: [256]u8 = undefined;
const resultado = std.mem.replace(u8, texto, "Olá", "Hello", &buf);
// resultado é o número de substituições feitas
// Para obter o tamanho final, precisamos calcular
const novo_tamanho = texto.len + resultado * ("Hello".len - "Olá".len);
try stdout.print("Original: \"{s}\"\n", .{texto});
try stdout.print("Substituído: \"{s}\"\n", .{buf[0..novo_tamanho]});
try stdout.print("Substituições: {d}\n", .{resultado});
}
Saída esperada:
Original: "Olá Mundo! Olá Zig!"
Substituído: "Hello Mundo! Hello Zig!"
Substituições: 2
Substituição com Alocação Dinâmica
Quando o tamanho do resultado é desconhecido ou variável, use um ArrayList.
const std = @import("std");
fn substituirTudo(
allocator: std.mem.Allocator,
texto: []const u8,
busca: []const u8,
substituicao: []const u8,
) ![]u8 {
var resultado = std.ArrayList(u8).init(allocator);
defer resultado.deinit();
var pos: usize = 0;
while (pos < texto.len) {
if (pos + busca.len <= texto.len and
std.mem.eql(u8, texto[pos .. pos + busca.len], busca))
{
try resultado.appendSlice(substituicao);
pos += busca.len;
} else {
try resultado.append(texto[pos]);
pos += 1;
}
}
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();
// Substituir texto curto por texto longo
const texto = "Zig é bom. Zig é rápido.";
const resultado = try substituirTudo(allocator, texto, "Zig", "A linguagem Zig");
defer allocator.free(resultado);
try stdout.print("Original: \"{s}\"\n", .{texto});
try stdout.print("Substituído: \"{s}\"\n", .{resultado});
// Substituir texto longo por curto (reduzir)
const html = "<b>texto</b> e <b>mais</b>";
const sem_bold = try substituirTudo(allocator, html, "<b>", "");
defer allocator.free(sem_bold);
const limpo = try substituirTudo(allocator, sem_bold, "</b>", "");
defer allocator.free(limpo);
try stdout.print("\nHTML: \"{s}\"\n", .{html});
try stdout.print("Limpo: \"{s}\"\n", .{limpo});
}
Saída esperada:
Original: "Zig é bom. Zig é rápido."
Substituído: "A linguagem Zig é bom. A linguagem Zig é rápido."
HTML: "<b>texto</b> e <b>mais</b>"
Limpo: "texto e mais"
Substituir Apenas a Primeira Ocorrência
const std = @import("std");
fn substituirPrimeiro(
allocator: std.mem.Allocator,
texto: []const u8,
busca: []const u8,
substituicao: []const u8,
) ![]u8 {
if (std.mem.indexOf(u8, texto, busca)) |pos| {
var resultado = std.ArrayList(u8).init(allocator);
defer resultado.deinit();
try resultado.appendSlice(texto[0..pos]);
try resultado.appendSlice(substituicao);
try resultado.appendSlice(texto[pos + busca.len ..]);
return resultado.toOwnedSlice();
}
// Se não encontrar, retornar uma cópia
return allocator.dupe(u8, texto);
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const texto = "foo bar foo baz foo";
const resultado = try substituirPrimeiro(allocator, texto, "foo", "qux");
defer allocator.free(resultado);
try stdout.print("Original: \"{s}\"\n", .{texto});
try stdout.print("Substituído: \"{s}\"\n", .{resultado});
}
Saída esperada:
Original: "foo bar foo baz foo"
Substituído: "qux bar foo baz foo"
Substituir Caractere por Caractere
Para substituições simples de caractere único, itere diretamente.
const std = @import("std");
fn substituirCaractere(allocator: std.mem.Allocator, texto: []const u8, antigo: u8, novo: u8) ![]u8 {
const resultado = try allocator.alloc(u8, texto.len);
for (texto, 0..) |c, i| {
resultado[i] = if (c == antigo) novo else c;
}
return resultado;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Substituir espaços por underscores
const nome = "meu arquivo de texto.txt";
const slug = try substituirCaractere(allocator, nome, ' ', '_');
defer allocator.free(slug);
try stdout.print("Slug: \"{s}\"\n", .{slug});
// Substituir pontos por hífens
const versao = "1.2.3";
const formatado = try substituirCaractere(allocator, versao, '.', '-');
defer allocator.free(formatado);
try stdout.print("Versão: \"{s}\"\n", .{formatado});
}
Saída esperada:
Slug: "meu_arquivo_de_texto.txt"
Versão: "1-2-3"
Exemplo Prático: Template Simples
Implemente um sistema básico de templates com substituição de variáveis.
const std = @import("std");
fn renderTemplate(
allocator: std.mem.Allocator,
template: []const u8,
variaveis: []const struct { chave: []const u8, valor: []const u8 },
) ![]u8 {
var resultado = try allocator.dupe(u8, template);
for (variaveis) |v| {
// Construir o placeholder: {{chave}}
const placeholder = try std.fmt.allocPrint(allocator, "{{{{{s}}}}}", .{v.chave});
defer allocator.free(placeholder);
// Substituir todas as ocorrências
var novo = std.ArrayList(u8).init(allocator);
defer novo.deinit();
var pos: usize = 0;
while (pos < resultado.len) {
if (pos + placeholder.len <= resultado.len and
std.mem.eql(u8, resultado[pos .. pos + placeholder.len], placeholder))
{
try novo.appendSlice(v.valor);
pos += placeholder.len;
} else {
try novo.append(resultado[pos]);
pos += 1;
}
}
allocator.free(resultado);
resultado = try novo.toOwnedSlice();
}
return resultado;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const template = "Olá, {{nome}}! Bem-vindo ao {{site}}. Seu ID é {{id}}.";
const variaveis = [_]struct { chave: []const u8, valor: []const u8 }{
.{ .chave = "nome", .valor = "Maria" },
.{ .chave = "site", .valor = "Zig Brasil" },
.{ .chave = "id", .valor = "12345" },
};
const resultado = try renderTemplate(allocator, template, &variaveis);
defer allocator.free(resultado);
try stdout.print("Template: {s}\n", .{template});
try stdout.print("Resultado: {s}\n", .{resultado});
}
Saída esperada:
Template: Olá, {{nome}}! Bem-vindo ao {{site}}. Seu ID é {{id}}.
Resultado: Olá, Maria! Bem-vindo ao Zig Brasil. Seu ID é 12345.
Veja Também
- Buscar Substrings — Encontre texto antes de substituir
- Concatenar Strings — Junte partes após substituição
- Dividir (Split) Strings — Divida e reconstrua com substituição
- Remover Espaços (Trim) — Limpe texto antes de substituir