Java Pattern.quote: ค้นข้อความผู้ใช้แบบ literal โดยไม่เปิด regex แฝง
ช่องค้นหาที่รับคำว่า a+b แล้วนำไปต่อใน regex จะไม่ได้ค้นเครื่องหมายบวกตามตัวอักษรครับ +, ., ( และสัญลักษณ์อื่นมีความหมายพิเศษ Pattern.quote เปลี่ยน input ให้เป็นส่วน literal ก่อนประกอบกับโครง regex ที่เราเป็นเจ้าของ
เหมือนใส่ชิ้นงานหยัก ๆ ลงปลอกใสก่อนส่งผ่านสายพาน รูปทรงด้านในยังเหมือนเดิม แต่ฟันเฟืองภายนอกจะไม่ตีความรอยหยักว่าเป็นคำสั่ง
import java.util.regex.Pattern;
public class Main {
static Pattern exactToken(String userText) {
return Pattern.compile("^" + Pattern.quote(userText) + "$");
}
public static void main(String[] args) {
Pattern literal = exactToken("a+b.(draft)");
assert literal.matcher("a+b.(draft)").matches();
assert !literal.matcher("aaabXdraft").matches();
String tricky = "end\\Estart";
assert exactToken(tricky).matcher(tricky).matches();
System.out.println("Pattern.quote tests passed");
}
}
Quote เฉพาะข้อมูล ไม่ quote โครงสร้าง
ถ้าต้องการค้นคำผู้ใช้ภายใน boundary ที่กำหนดเอง ให้ quote เฉพาะคำนั้น เช่น prefix + Pattern.quote(input) + suffix อย่า quote ทั้ง expression เพราะ anchor หรือ group ที่เราตั้งใจจะกลายเป็นตัวอักษรธรรมดา และอย่าเขียน "\\Q" + input + "\\E" เอง เพราะ input อาจมีลำดับ \E; method มาตรฐานจัดการกรณีนี้ให้
หากโจทย์เป็นเพียง substring แบบ case-sensitive ใช้ String.contains อ่านง่ายกว่า regex ถ้าต้องเปลี่ยน replacement text ใช้ Matcher.quoteReplacement ซึ่งแก้คนละ boundary เพราะ $ และ backslash มีความหมายใน replacement ส่วนระบบค้นหาที่รับ regex จริงจากผู้ใช้ต้องมี timeout/limit และ UX บอกชัด ไม่ควรแอบลดให้เป็น literal
Recap
- quote ทุกส่วนที่มาจากผู้ใช้ก่อนใส่ใน regex
- เก็บ anchor/group ที่แอปควบคุมไว้นอก quoted segment
- ใช้
containsเมื่อไม่ต้องการพลังของ regex - ใช้
quoteReplacementสำหรับ replacement string ไม่ใช่ pattern