Zig indexOfScalarPos: ค้นตัวคั่นต่อจาก cursor โดยไม่ตัด slice ซ้ำ
parser ขนาดเล็กมักถือ cursor แล้วหาตัวคั่นถัดไป ถ้าตัด input[cursor..] ทุกครั้ง เราต้องบวก offset กลับเองและเสี่ยงพลาดหนึ่งตำแหน่งครับ std.mem.indexOfScalarPos รับ slice, ตำแหน่งเริ่ม และตัวที่ต้องหา แล้วคืน index บน slice เดิม
WHY: index ทุกตัวอยู่ในพิกัดเดียวกัน
เหมือนบอกพนักงานว่า “เริ่มค้นจากชั้นสี่ของตู้เดิม” แทนการยกครึ่งตู้มาเป็นตู้ใหม่ หมายเลขชั้นที่ได้จึงอ้างถึงข้อมูลต้นฉบับตลอด เหมาะกับ parser ที่ต้องบันทึกช่วง error หรือส่ง slice ย่อยต่อ
HOW: รองรับทั้งเจอและไม่เจอ
const std = @import("std");
test "find delimiter after the cursor" {
const input = "red,green,blue";
const comma = std.mem.indexOfScalarPos(u8, input, 4, ',');
try std.testing.expectEqual(@as(?usize, 9), comma);
}
test "return null when no delimiter remains" {
const input = "red,green,blue";
const comma = std.mem.indexOfScalarPos(u8, input, 10, ',');
try std.testing.expectEqual(@as(?usize, null), comma);
}
ผลลัพธ์เป็น optional index หรือ ?usize เพราะตัวคั่นอาจไม่มี การใช้ if (comma) |index| { ... } else { ... } ทำให้ทางจบ record สุดท้ายชัด อย่าใช้ .? ถ้าข้อมูลมาจากผู้ใช้ เพราะ input ที่ไม่มี delimiter จะกลายเป็น panic แทน error ที่อธิบายได้
สำหรับ Unicode ต้องจำว่า slice ของ Zig มักเป็น bytes ตำแหน่งที่ได้จึงเป็น byte offset ไม่ใช่จำนวนตัวอักษรที่มนุษย์เห็น ถ้าตัวคั่นเป็น ASCII เช่น comma หรือ newline ใช้ได้ตรงไปตรงมา แต่การค้น code point ต้อง decode UTF-8 ตาม contract ของข้อมูล
Recap
- ส่ง cursor เข้า
indexOfScalarPosเพื่อคงพิกัดบน slice เดิม - จัดการ
nullเป็นทางปกติของ record สุดท้าย - หลีกเลี่ยง force unwrap กับ input ภายนอก
- แยก byte offset ออกจากตำแหน่งอักขระ Unicode