Chỉ thêm cờ g vào regex nhưng mã đang đọc result[1] bỗng lấy nhầm dữ liệu. Với String.match, bật tìm kiếm toàn cục còn thay đổi cấu trúc kết quả. Cần xem cả regex lẫn đoạn đọc đầu ra khi sửa một phép trích xuất.
1. Không có g: một lần khớp kèm nhóm bắt
const text = 'item-42 item-7';
const result = text.match(/item-([0-9]+)/);
console.log(result[0]); // item-42
console.log(result[1]); // 42
console.log(result.index); // 0
Trong ví dụ, vị trí 0 chứa toàn bộ đoạn khớp và vị trí 1 chứa nhóm chữ số đầu tiên. Xem quy tắc đầu ra trong MDN String.match. Việc đọc trực tiếp result[1] ở đây dựa trên chuỗi đã biết chắc có kết quả.
Với văn bản tùy ý, bước gọi match phải được theo sau bằng kiểm tra có khớp hay không. Một chuỗi không đúng mẫu không nên âm thầm biến thành mã mặc định nếu điều đó che mất lỗi dữ liệu nguồn.
2. Có g: mảng chứa các đoạn khớp đầy đủ
const text = 'item-42 item-7';
const result = text.match(/item-([0-9]+)/g);
console.log(JSON.stringify(result)); // ["item-42","item-7"]
console.log(result[1]); // item-7
result[1] trong phiên bản này là đoạn khớp thứ hai, không phải nhóm chữ số của đoạn đầu. Vì cả hai kết quả đều là chuỗi, lỗi có thể không gây exception mà chỉ đi tiếp với dữ liệu sai.
Test chỉ dùng một mã có thể cho undefined ở vị trí 1, còn test dùng hai mã sẽ cho một chuỗi có vẻ hợp lệ. Vì vậy cần kiểm tra cả số lượng kết quả và cấu trúc của từng mục, không chỉ kiểm tra result tồn tại.
3. Dùng matchAll khi cần nhóm bắt của từng lần khớp
function extractItemIds(text) {
if (typeof text !== 'string') throw new TypeError('text must be a string');
return [...text.matchAll(/item-([0-9]+)/g)]
.map(match => match[1]);
}
console.log(JSON.stringify(extractItemIds('item-42 item-7'))); // ["42","7"]
console.log(JSON.stringify(extractItemIds('item-007'))); // ["007"]
matchAll trả iterator gồm các kết quả có nhóm bắt; regex truyền vào ở đây có cờ g. Tham khảo MDN String.matchAll. Helper chuyển kết quả thành mảng một lần rồi lấy nhóm số 1.
Các ID được giữ dưới dạng chuỗi để không tự loại số 0 đầu hoặc áp một quy tắc số học ngoài ý muốn. Regex chỉ minh họa việc tìm các đoạn item theo sau bằng chữ số ASCII; nó chưa xác nhận toàn bộ đầu vào đúng một định dạng bản ghi.
Chẳng hạn, văn bản có ký tự thừa vẫn có thể chứa một đoạn khớp. Nếu đang xác thực một trường chỉ được chứa đúng một mã, hãy dùng contract khác phù hợp với toàn bộ trường. Trích xuất nhiều đoạn trong văn bản và xác thực một giá trị là hai yêu cầu khác nhau.
4. Không có kết quả: null khác với iterator rỗng
const text = 'nothing here';
console.log(text.match(/item-([0-9]+)/) === null); // true
console.log(text.match(/item-([0-9]+)/g) === null); // true
console.log([...text.matchAll(/item-([0-9]+)/g)].length); // 0
Trong hai lần gọi match, không có kết quả trả null. matchAll cho phép tạo mảng rỗng từ iterator không có mục. Thiết kế kiểu đầu ra của helper rõ ràng giúp phần gọi phân biệt không tìm thấy với lỗi đầu vào không phải chuỗi.
Nếu màn hình cần thông báo “Không tìm thấy mã”, danh sách rỗng là một trạng thái có thể xử lý chủ động. Nếu quá trình import bắt buộc có ít nhất một mã, đặt kiểm tra đó sau bước trích xuất thay vì dựa vào truy cập phần tử làm phát sinh lỗi.
5. Review khi thay đổi flags hoặc nhóm bắt
- Kiểm tra nơi dùng result[0], result[1] và các thuộc tính kết quả.
- Thử văn bản không khớp, một lần khớp và nhiều lần khớp.
- Giữ ID dạng chuỗi nếu contract cần giữ số 0 đầu.
- Phân biệt trích xuất một phần văn bản với xác thực toàn bộ trường.
- Kiểm tra regex truyền cho matchAll có cờ g.
Tám khối mã Việt–Anh đã chạy bằng Node.js, kèm kiểm tra helper với chuỗi rỗng, mã lặp, số 0 đầu và đầu vào sai kiểu. Chưa tích hợp parser import hoặc dữ liệu production.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.