Reminder that, despite the title of this example, the concept of string
doesn't actually exist in Zig. Instead, a string is an array of bytes
(u8
).
Which is why, most of the functions here will also work to handle arrays
whose individual types are not u8
.
Copy
const std = @import("std");
test "String copy" {
const allocator = std.testing.allocator;
const message = "The quick brown fox.";
const copied = try allocator.alloc(u8, message.len);
defer allocator.free(copied);
std.mem.copy(u8, copied, message);
std.debug.print("\nOriginal: {s}\n Copy: {s}\n", .{ message, copied });
}
$ zig test string_handling.zig
Test [1/1] test "String copy"...
Original: The quick brown fox.
Copy: The quick brown fox.
All 1 tests passed.
$ █
Alternatively, if you're using an allocator, you can instead duplicate the
string by using Allocator.dupe()
.
const std = @import("std");
test "String copy/dupe" {
const allocator = std.testing.allocator;
const message = "The quick brown fox.";
const copied = try allocator.dupe(u8, message);
defer allocator.free(copied);
std.debug.print("\nOriginal: {s}\n Copy: {s}\n", .{ message, copied });
}
$ zig test string_handling.zig
Test [1/1] test "String copy/dupe"...
Original: The quick brown fox.
Copy: The quick brown fox.
All 1 tests passed.
$ █
Equal
const std = @import("std");
test "String equal" {
const allocator = std.testing.allocator;
const message = "The quick brown fox.";
const copied = try allocator.dupe(u8, message);
defer allocator.free(copied);
const is_equal = std.mem.eql(u8, copied, message);
std.debug.print("\nOriginal: {s}\n Copy: {s}\n", .{ message, copied });
std.debug.print("Are the two strings equal? {}\n", .{is_equal});
try std.testing.expect(is_equal);
}
$ zig test string_handling.zig
Test [1/1] test "String equal"...
Original: The quick brown fox.
Copy: The quick brown fox.
Are the two strings equal? true
All 1 tests passed.
$ █
Be extra careful when using this function to compare C null-terminated
array, however, as, unlike C's strcmp
, this function
doesn't stop when it reaches a zero value.
const std = @import("std");
test "String equal" {
const message0 = "Equal?";
const message1 = &[_]u8{ 'E', 'q', 'u', 'a', 'l', '?', 0, 0 };
const is_equal = std.mem.eql(u8, message0, message1);
try std.testing.expect(is_equal);
}
$ zig test string_handling.zig
Test [2/1] test "String equal"... FAIL (TestUnexpectedResult)
/home/zig/std/testing.zig:309:14: 0x7ff6d97231fb in std.testing.expect (test.obj)
if (!ok) return error.TestUnexpectedResult;
^
/home/zig/test.zig:9:5: 0x7ff6d9721890 in test "String equal" (test.obj)
try std.testing.expect(is_equal);
^
0 passed; 0 skipped; 1 failed.
error: the following test command failed with exit code 1:
zig-cache/o/12cf2178032725d246a4b465b2a8361b/test /home/zig/zig
$ █
One way to solve this is by counting how many bytes it takes until it reaches the zero value, then create a slice out of it.
const std = @import("std");
test "String equal" {
const message0 = "Equal?";
const message1 = &[_]u8{ 'E', 'q', 'u', 'a', 'l', '?', 0, 0 };
var message1_length: usize = 0;
for (message1) |byte| {
if (byte == 0) break;
message1_length += 1;
}
const message1_slice = message1[0 .. message1_length];
const is_equal = std.mem.eql(u8, message0, message1_slice);
try std.testing.expect(is_equal);
}
$ zig test string_handling.zig
All 1 tests passed.
$ █
Or alternatively, you can just use std.mem.sliceTo()
:
const std = @import("std");
test "String equal" {
const message0 = "Equal?";
const message1 = &[_]u8{ 'E', 'q', 'u', 'a', 'l', '?', 0, 0 };
const message1_slice = std.mem.sliceTo(message1, 0);
const is_equal = std.mem.eql(u8, message0, message1_slice);
try std.testing.expect(is_equal);
}
$ zig test string_handling.zig
All 1 tests passed.
$ █
Contains
To check whether a substring is present in a given string, you can use
std.mem.count()
.
std.mem.count()
returns how many times a substring is detected
inside the string.
const std = @import("std");
test "String contains" {
const message = "Hello, world!";
var contains = if (std.mem.count(u8, message, "Hell") > 0) true else false;
try std.testing.expect(contains);
contains = if (std.mem.count(u8, message, "What") > 0) true else false;
try std.testing.expect(!contains);
}
$ zig test string_handling.zig
All 1 tests passed.
$ █