2 more convenient API have been added!
re.split(haystack) creates an iterator that returns all spans of the haystack split by matched regex.
test "usage: split" {
const gpa = testing.allocator;
var re = try Regex.compile(gpa, "[ \\t]+", .{});
defer re.deinit();
const haystack = "a b \t c";
var iter = re.split(haystack);
try expectEqualStrings("a", iter.next().?.bytes(haystack));
try expectEqualStrings("b", iter.next().?.bytes(haystack));
try expectEqualStrings("c", iter.next().?.bytes(haystack));
try expectEqual(null, iter.next());
}
re.replace and its variations are meant to turn matched bytes into the provided replacement bytes.
The base API is
pub fn replace(re: Regex, writer: std.Io.Writer, haystack: []const u8, replacement: []const u8) Writer.Error!bool
It takes a std.Io.Writer to allow caller control over the allocation of the result. If there is a match in haystack (first match), it writes the byte slice before the match, the replacement bytes, and the byte slice after the match.
The Alloc variation is a convenience method that allocates and returns result byte slice, which also serves as an example of how to use the base API.
pub fn replaceAlloc(re: Regex, gpa: std.mem.Allocator, haystack: []const u8, replacement: []const u8) !?[]const u8
The All variation replaces all matches in haystack with replacement instead of just the first match.
pub fn replaceAll(re: Regex, writer: std.Io.Writer, haystack: []const u8, replacement: []const u8) Writer.Error!bool
Finally, replacement arg is a template - if it contains tokens such as $1 or ${name} which reference the capture groups of the matched regex, then those tokens will be expanded into the capture groups of the match. See examples below.
test "usage: replace" {
const gpa = testing.allocator;
var w: std.Io.Writer.Allocating = .init(gpa);
defer w.deinit();
const writer = &w.writer;
{
var re: Regex = try .compile(gpa, " ", .{});
defer re.deinit();
{
// Replace with std.Io.Writer API
const replaced_once = try re.replace(writer, "a b c d", "X");
try testing.expect(replaced_once);
try testing.expectEqualStrings("aXb c d", w.written());
}
{
// Replace, but allocate the result in the bytes
const mb_replaced = try re.replaceAlloc(gpa, "a b c d", "X");
const replaced = mb_replaced orelse return error.TestUnexpectedResult;
defer gpa.free(replaced);
try testing.expectEqualStrings("aXb c d", replaced);
}
{
// Replace all matched instances, with std.Io.Writer API
w.clearRetainingCapacity();
const replaced = try re.replaceAll(writer, "a b c d", "X");
try testing.expect(replaced);
try testing.expectEqualStrings("aXbXcXd", w.written());
}
{
// Replacement text can be used as a template to to expand capture groups in matched text
var re: Regex = try .compile(gpa, "(\\w+) (\\d+), (?<year>\\d+)", .{});
defer re.deinit();
w.clearRetainingCapacity();
const replaced = try re.replace(writer, "July 17, 2026", "${year}-$1-$2");
try testing.expect(replaced);
try testing.expectEqualStrings("2026-July-17", w.written());
}
}
There are more low level API in the code Regex.zig which is quite easy to read - feel free to peruse!
With this I believe most useful APIs are covered. If you’re interested in taking up this library as a dependency, and have some uncovered use cases please hit me up!