การจัดการข้อความเป็นเรื่องที่พบมากในการเขียนโปรแกรม เพราะข้อมูลที่เราเอามาให้โปรแกรมประมวลผลรวมถึงผลลัพธ์ที่ได้จากโปรแกรมมักจะเป็นข้อความ เช่น การค้นหาเนื้อหาที่ต้องการจากคีย์เวิร์ดที่ระบุด้วยเครื่องมือค้นหาอย่างกูเกิ้ล การตรวจสอบความถูกต้องของข้อมูลที่ผู้ใช้งานกรอกลงในแบบฟอร์ม การส่ง/รับข้อมูลระหว่างเซิร์ฟเวอร์ด้วยรูปแบบ xml ก็เป็นข้อความ
ปัญหาหลักๆจากการจัดการข้อความก็คือความหลากหลายของข้อมูลที่มีความหมายเดียวกันกับที่เราต้องการ เช่น หากเราต้องการหาบทความที่เกี่ยวกับสี เราต้องค้นหาด้วยคีย์เวิร์ด colour และ color เพราะมีการใช้การสะกดทั้ง 2 แบบ หรือหากเราต้องการตรวจสอบว่าผู้ใช้งานกรอกรหัสสมาชิกถูกต้องหรือไม่ เราจะตรวจสอบอย่างไร หรือ เราจะแยกแยะข้อมูลตามชนิดของข้อมูลที่บอกมาใน tag ของข้อความในรูปแบบ xml อย่างไร ปัญหาเหล่านี้เราสามารถใช้ regex ช่วยให้ง่ายขึ้นได้
regular expression หรือ regx หรือ regxp คือชุดของอักขระที่แสดงรูปแบบ (pattern) ของข้อความที่เราต้องการ เราใช้ regx ในการจับคู่กับข้อความที่ต้องการเพื่อค้นหา แก้ไข หรือจัดการข้อความ เช่น เรากำหนด regex เป็น colou?r เพื่อให้สามารถค้นหาทั้ง colour และ color เรากำหนด regex เป็น [1-3]-[0-9]{5}-16 เพื่อตรวจสอบรูปแบบของรหัสสมาชิกว่าถูกต้องหรือไม่ เป็นต้น
Java API กำหนดการใช้ regular expression ไว้ในแพคเกจ java.util.regex ซึ่งประกอบไปด้วยคลาสแบบอินเตอร์เฟส MatchResult คลาส Matcher และคลาส Pattern โดยมีคลาส PatternSyntaxException เป็นตัวจัดการข้อยกเว้น คลาส Pattern จะทำหน้าที่ในการคอมไพล์ regex ของเราเพื่อให้คลาส Matcher นำไปใช้งาน
ตัวอย่างการใช้งาน
Pattern p = Pattern.compile(“a*b”); // คอมไพล์ regex ที่เรากำหนดและเก็บไว้ที่ตัวแปร p
Matcher m = p.matcher(“aaaaab”); // ใช้เมธอด matcher จากคลาส Pattern เพื่อสร้างตัวจับคู่ขึ้นมา
boolean b = m.matches(); // ใช้ตัวจับคู่เพื่อหาผลลัพธ์และตอบกลับว่าพบหรือไม่
หรือสามารถเขียนได้เป็น
boolean b = Pattern.matches(“a*b”, “aaaaab”);
ซึ่งการใช้งานในแบบหลังจะปลอดภัยกว่าสำหรับการเขียนโปรแกรมแบบมัลติเธรด ในภาษาจาวาการเทียบหาข้อความในตัวแปรชนิด String จะต้องกำหนด regex เหมือนกันแบบ 100% ถึงจะหาพบ ซึ่งเราสามารถใช้อักขระพิเศษ เช่น . หรือ ? ช่วยในการกำหนดรูปแบบการค้นหาได้ ดังตัวอย่างด้านล่าง ข้อความที่เราใช้เป็นโจทย์ในการค้นหาคือ this is test text สังเกตว่าเราค้นหาคำว่า test ผลลัพธ์คือไม่พบ (false) ทั้งที่เราเข้าใจว่ามันน่าจะพบ แต่ถ้าค้นหาด้วยประโยคเต็มผลลัพธ์คือพบ (true) ใน แต่ถ้าเราใช้ ” .* ” ช่วยโดยระบุทั้งด้านหน้าและด้านหลังของ test ผลลัพธ์คือพบ (true) ซึ่ง ” .* ” หมายถึงอักขระอะไรก็ได้ กี่ตัวก็ได้ ซึ่งตอบโจทย์สิ่งที่ภาษาจาวาต้องการคือเหมือนกันทั้งข้อความ
package com.company;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String str = "this is test text";
// match with "test"
Pattern p1 = Pattern.compile("test");
Matcher m1 = p1.matcher(str);
boolean b1 = m1.matches();
System.out.println("b1 : " + b1);
// match with full sentence
Pattern p2 = Pattern.compile("this is test text");
Matcher m2 = p2.matcher(str);
boolean b2 = m2.matches();
System.out.println("b2 : " + b2);
// match with special character
Pattern p3 = Pattern.compile(".*test.*");
Matcher m3 = p3.matcher(str);
boolean b3 = m3.matches();
System.out.println("b3 : " + b3);
}
}
b1 : false
b2 : true
b3 : true
จากตัวอย่างจะเห็นว่าการจับคู่ด้วยข้อความ test ไม่สำเร็จ แต่การจับคู่ด้วยข้อความเต็มหรือใช้ใช้อักขระพิเศษช่วยจะสามารถจับคู่กับข้อความที่ต้องการได้
ตัวอย่างรูปแบบที่ใช้ในการสร้าง regex
. หมายถึงอักขระใดก็ได้
x หมายถึงตัวอักษร เช่น “a” , “test”
\\ หมายถึงอักขระ back slash ()\ เช่น “\\”
\t หมายถึงอักขระ tab
\n หมายถึงอักขระขึ้นบรรทัดใหม่
\\. หมายถึงอักขระ dot (.)
\\? หมายถึงอักขระ ?
[abc] หมายถึงในตำแหน่งที่กำหนดตัวอักษรอาจจะเป็น a หรือ b หรือ c ก็ได้
[^abc] หมายถึงในตำแหน่งที่กำหนดตัวอักษรอาจจะเป็นอะไรก็ได้ที่ไม่ใช่ a หรือ b หรือ c
[a-z] หมายถึงในตำแหน่งที่กำหนดเป็นตัวอักษร a-z (ตัวอักษรเล็ก)
[A-Z] หมายถึงในตำแหน่งที่กำหนดเป็นตัวอักษร A-Z (ตัวอักษรใหญ่)
[a-zA-Z] หมายถึงในตำแหน่งที่กำหนดเป็นตัวอักษร a-z หรือ A-Z
\\d หมายถึงในตำแหน่งที่กำหนดเป็นตัวเลข 0 – 9
\\D หมายถึงในตำแหน่งที่กำหนดต้องไม่เป็นตัวเลข 0 – 9
\\s หมายถึงอักขระว่างทั้งหมดคือ [\t\n\x0B\f\r]
\\w หมายถึงตัวอักษรและตัวเลขคือ a-z A-Z และ 0-9
\\W หมายถึงไม่ใช่ตัวอักษรและตัวเลข หมายถึงในตำแหน่งที่กำหนดจะเป็นอักขระใดก็ได้จำนวน 1 ตัว
X? หมายถึงอักขระที่ต้องการในตำแหน่งที่กำหนดจะมีหรือไม่มีก็ได้
X* หมายถึงอักขระที่ต้องการในตำแหน่งที่กำหนดอาจจะมีหนึ่งตัวหรือหลายตัวก็ได้
+ หมายถึงอักขระที่อยู่หน้า + มีได้ตั้งแต่หนึ่งอักขระขึ้นไป และ * หมายถึงอักขระที่อยู่หน้า + อาจจะไม่มีหรือมีได้ตั้งแต่หนึ่งอักขระขึ้นไป
{n} หมายถึงอักขระที่อยู่หน้า {n} มีจำนวน n อักขระ
{n,m} หมายถึงอักขระที่อยู่หน้า {n,m} มีจำนวนอย่างน้อย n อักขระแต่ไม่เกิน m อักขระ
{n,} หมายถึงอักขระที่อยู่หน้า {n,} มีจำนวนอย่างน้อย n อักขระ
{0,m} หมายถึงอักขระที่อยู่หน้า {0,m} มีจำนวนไม่เกิน m อักขระ
ตัวอย่างด้านบนเป็นการกำหนดรูปแบบสำหรับอักขระแบบเดี่ยวๆ เราสามารถกำหนดเป็นข้อความได้โดยการใช้เครื่องหมาย | ตัวอย่างเช่น .*|test|.* เพื่อจับคู่คำว่า test ซึ่งนำหน้าและตามหลังด้วยอะไรก็ได้ กี่อักขระก็ได้
สำหรับรูปแบบทั้งหมดสามารถดูได้ที่ https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/regex/Pattern.html
เราสามารถทดสอบ regex ได้ที่ https://regex101.com/