Zig tokenizeSequence: แยกข้อมูลด้วย delimiter หลายไบต์แบบไม่ตัดกลาง
protocol เล็ก ๆ มักคั่น field ด้วยลำดับหลายไบต์ เช่น :: ถ้าใช้ตัวแบ่งแบบ “เจอ colon ตัวใดก็ได้” ข้อมูลอย่างเวลา 10:30 จะถูกตัดผิด std.mem.tokenizeSequence จับ delimiter ทั้งชุดและคืน slice ของ token โดยไม่ allocate สำเนาครับ
WHY: กรรไกรต้องรอหมุดครบคู่
ให้นึกถึงริบบิ้นที่ทำเครื่องหมายตัดด้วยหมุดสองเม็ดติดกัน กรรไกรไม่ควรตัดเมื่อเห็นหมุดเม็ดแรกตัวเดียว tokenizeSequence ต่างจาก tokenizeAny ตรงที่ทุก element ใน delimiter ต้องเรียงติดกันครบชุด
const std = @import("std");
fn collectThree(input: []const u8) ![3][]const u8 {
var it = std.mem.tokenizeSequence(u8, input, "::");
const first = it.next() orelse return error.MissingField;
const second = it.next() orelse return error.MissingField;
const third = it.next() orelse return error.MissingField;
if (it.next() != null) return error.TooManyFields;
return .{ first, second, third };
}
test "sequence delimiter stays intact" {
const fields = try collectThree("room::10:30::ready");
try std.testing.expectEqualStrings("room", fields[0]);
try std.testing.expectEqualStrings("10:30", fields[1]);
try std.testing.expectEqualStrings("ready", fields[2]);
try std.testing.expectError(error.MissingField, collectThree("room::::ready"));
try std.testing.expectError(error.TooManyFields, collectThree("a::b::c::d"));
}
HOW: token ว่างถูกข้าม
คำว่า tokenize หมายถึงข้าม delimiter ที่ติดกันและไม่คืน token ว่าง ดังนั้น room::::ready มีเพียงสอง token ไม่ใช่สาม field ที่ตรงกลางว่าง ถ้า empty field มีความหมาย ให้ใช้ splitSequence แทนและ validate จำนวนช่องตาม schema
token ที่ได้อ้างอิง buffer ต้นฉบับ ห้ามปล่อย buffer หมดอายุแล้วเก็บ slice ไว้ต่อ ส่วน UTF-8 เป็นเพียง byte sequence สำหรับ API นี้ ถ้า delimiter หรือ input อาจตัดกลาง code point ต้องกำหนด encoding contract และ validate ข้อความก่อน parse
Recap
- ใช้
tokenizeSequenceเมื่อ delimiter ต้องตรงทั้งชุด - ใช้
splitSequenceหากช่องว่างระหว่าง delimiter มีความหมาย - จำกัดจำนวน field และขนาด input ก่อน parse
- รักษาอายุ buffer ให้ยาวกว่า token slices
- ทดสอบ delimiter ซ้ำ ขาด field เกิน field และข้อมูลที่มี delimiter บางส่วน