Я новичок в зигзаге и изучаю его. Поэтому я попытался написать свою собственную функцию разделения юникода (по причинам, пожалуйста, побалуйте меня). Вот:
fn split_utf8(allocator: std.mem.Allocator, in: []const u8, delimiter: []const u8) !std.ArrayList([]const u8) {
var list = std.ArrayList([]const u8).init(allocator);
try list.append("");
var utf8 = (try std.unicode.Utf8View.init(in)).iterator();
while (utf8.nextCodepointSlice()) |codepoint| {
if (std.mem.eql(u8, codepoint, delimiter)) {
try list.append("");
continue;
}
const last: []const u8 = list.pop();
defer allocator.free(last);
const new: []const u8 = std.mem.concat(allocator, u8, &[_][]const u8{last, codepoint}) catch "Something went really wrong";
try list.append(new);
}
return list;
}
test "Split test" {
var expected = std.ArrayList([]const u8).init(std.testing.allocator);
defer expected.deinit();
try expected.append("F");
try expected.append("1");
try expected.append("100");
try expected.append("📷click");
const actual = try split_utf8(std.testing.allocator, "F 1 100 📷click", " ");
defer actual.deinit();
try testing.expectEqual(expected.items.len, actual.items.len);
// further testing
}
но я всегда получаю сообщение об ошибке, связанное с утечкой адреса, созданного std.mem.concat. Я пробовал следующие вещи:
Я очень растерян. Я хотел бы знать, как исправить метод Split_utf8? Возможно, в будущем появится список растущих вещей. Спасибо!
Хорошо, я понял, что сделал не так; splitAny
— это была функция, которую я искал, возможно, я раньше использовал ее неправильно. Остается еще второй вопрос, который имеет совершенно другую природу, а именно управление памятью. Думаю, в будущем мне придется написать массив растущих вещей, есть ли у вас какие-нибудь советы? Также редактируем вопрос, чтобы лучше отразить этот новый вопрос.
Вы не освобождаете отдельные строки, которые есть в списке массива.
Сделайте что-то вроде этого:
const actual = try split_utf8(std.testing.allocator, "F 1 100 📷click", " ");
defer {
for (actual.items) |str| {
std.testing.allocator.free(str);
}
actual.deinit();
}
Также:
const new: []const u8 = std.mem.concat(allocator, u8, &[_][]const u8{last, codepoint}) catch "Something went really wrong";
catch
здесь совершенно неправильный. Просто используйте try
. И добавьте оператор errdefer
после этой строки. Так:
const new: []const u8 = try std.mem.concat(allocator, u8, &[_][]const u8{last, codepoint});
errdefer allocator.free(new);
Я бы рекомендовал не использовать эту реализацию, так как она очень неэффективна. Для каждого символа во входной строке есть вызовы выделения и освобождения.
«splitAny или SplitSequence или tokenize… оно возвращает мусор» — я думаю, вам стоит сначала разобраться, что не так с вашим кодом, использующим эти функции, прежде чем пытаться углубиться в написание чего-то более сложного.