Search code examples
stringzig

How can I replace all instances of a character in a string in Zig?


If I have a "string" in zig ([]const u8) how can I replace a certain char (u8) with a different char? For example, lets say that I want to replace all underscores in a string with spaces.

I tried to write a method:

fn remove_underscores(str: []const u8) []const u8 {
    var output: []u8 = undefined;
    _ = std.mem.replace(u8, str, "_", "", output);
    return output;
}

but upon using the method, I got a segmentation fault at address 0x0

zig build test
run test: error: Segmentation fault at address 0x0
/usr/lib/zig/std/mem.zig:3603:30: 0x27604b in replace__anon_9374 (test)
            output[i] = input[slide];
                             ^
filepath: 0x262bb2 in replace_underscores (test)
        _ = std.mem.replace(u8, str, "_", " ", output);
                           ^
filepath: 0x2305ad in tokenize_numeric (test)
        _ = replace_underscores(num);
                               ^
filepath: 0x227efb in next (test)
            '0'...'9' => tokenize_numeric(self.read_number()),
                                         ^
filepath: 0x228064 in test.tokenize numbers (test)
        const actual = lexer.next();
                                 ^
/usr/lib/zig/test_runner.zig:100:29: 0x22eac4 in mainServer (test)
                test_fn.func() catch |err| switch (err) {
                            ^
/usr/lib/zig/test_runner.zig:34:26: 0x226bdd in main (test)
        return mainServer() catch @panic("internal test runner failure");
                         ^
/usr/lib/zig/std/start.zig:564:22: 0x226262 in posixCallMainAndExit (test)
            root.main();
                     ^
/usr/lib/zig/std/start.zig:243:5: 0x225db1 in _start (test)
    asm volatile (switch (native_arch) {
    ^
???:?:?: 0x1 in ??? (???)
Unwind information for `???:0x1` was not available, trace may be incomplete

Solution

  • It crashed because you left output uninitialized. You also need to allocate memory for it:

    const size = std.mem.replacementSize(u8, str, "_", " ");
    var output = try allocator.alloc(u8, size);
    _ = std.mem.replace(u8, str, "_", " ", output);
    

    There's an important question you need to be able to answer: where are the bytes?

    Since you need to replace a byte with a byte, you can use std.mem.replaceScalar:

    var output = try allocator.dupe(u8, str);
    std.mem.replaceScalar(u8, output, '_', ' ');