const std = @import("std"); const eql = std.mem.eql; pub const Error = error{InvalidUtf8} || std.mem.Allocator.Error; pub fn escape(alloc: std.mem.Allocator, v: []const u8) Error![]const u8 { var acc = try std.ArrayList(u8).initCapacity(alloc, v.len); errdefer acc.deinit(alloc); const view = try std.unicode.Utf8View.init(v); var iter = view.iterator(); while (iter.nextCodepointSlice()) |rune| { if (eql(u8, rune, "&")) { try acc.appendSlice(alloc, "&"); } else if (eql(u8, rune, "'")) { try acc.appendSlice(alloc, "'"); } else if (eql(u8, rune, "<")) { try acc.appendSlice(alloc, "<"); } else if (eql(u8, rune, ">")) { try acc.appendSlice(alloc, ">"); } else if (eql(u8, rune, "\"")) { try acc.appendSlice(alloc, """); } else { try acc.appendSlice(alloc, rune); } } return acc.toOwnedSlice(alloc); } fn doTest(alloc: std.mem.Allocator, el: []const u8, exp: []const u8) !void { const got = try escape(alloc, el); defer alloc.free(got); std.testing.expect(eql(u8, got, exp)) catch |err| { std.debug.print("{s}\n", .{got}); return err; }; } test "escaping html" { const alloc = std.testing.allocator; try doTest(alloc, "hello world", "hello world"); try doTest(alloc, "hello&world", "hello&world"); try doTest(alloc, "hello'world", "hello'world"); try doTest(alloc, "helloworld", "hello>world"); try doTest(alloc, "hello\"world", "hello"world"); }