นากกายต้นฉบับกำลังสอดชิ้นส่วนรูปทรงซับซ้อนเข้าแขนเสื้อใสก่อนนำไปเทียบกับแถวชิ้นงาน

Java Pattern.quote: ค้นข้อความผู้ใช้แบบ literal โดยไม่เปิด regex แฝง

พี่โชว์Engineering

ช่องค้นหาที่รับคำว่า 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