[REGEX] ดักจับ Pattern ของ ISO8601 Repeating Interval

ช่วงนี้ก็ยุ่งๆครับ พยายามดัน ตัว Tool และ Paper ของงานวิจัยครับ โดยสำหรับผมทำเกี่ยวกับ BPMN พวกวันทีเวลาทั้งหลายเนี่ย มันจะถูกจัดเก็บในรูปแบบมาตรฐาน ISO8601 ครับ หลายคนอาจจะคิดว่ามันไกลตัว แต่จริงๆมันแทรกซึมได้ไปในวิถี Developer แล้วครัับ เพราะ ISO8601 ถูกบรรจุในมาตรฐานของ JSON ครับ ลองดูว่าคุ้นๆกันไหมเอ่ยยย

{
   "json_date" : "2019-01-01T00:00:00Z"
}

DateTime เห็นกันบ่อยครับ แต่ที่แปลก และน่าจะถูกลืมน่าจะเป็นพวก

  • Time intervals - ช่วงเวลาครับ เช่น PT30M (ช่วงละ 30 นาที)
  • Repeating Interval - รอบ + ช่วงเวลาครับ R2/PT30M (ทำ 2 รอบ แต่ละรอบทิ้งช่วงห่างกัน 30 นาทีครับ)

ที่ถูกลืม เพราะ มันมีสิ่งที่น่าจะมาก่อนแล้วอย่าง CRON Format ครับ หรือชาวเพนกินเรียกว่่า CRON JOB ครับ

เกริ่นนำมายาวพอสมควรเลยครับ คราวนี้มาลองดูว่าปัญหาที่ผมเจอ คือ อะไร ถ้าเป็น

  • DateTime ทั่วไป Java Date สามารถแปลงได้ครับ
  • Time intervals ต้องใช้ Java 8 Duration กับ LocalDateTime มาช่วยครับ
  • แต่ Repeating Interval หมดสิทธิ์ครับ ตัวมา SubString แปลงเองครับ

มาที่ตัว Repeating Interval มันมี Combination แบบไหนได้บ้าง เท่าที่ผมเข้าใจนะ

  • {R[N]} / {DateTime} / {Interval} เช่น R2/2012-01-01T00:00:00Z/P1Y2DT0H3M
  • {R[N]}/{Interval} เช่น R2/PT3M

มาที่พระเอกของเราแล้วครับ โดยสังเกตุได้ว่า {R[N]}/{Interval} ต้องมาคู่กันครับ ถ้าเขียน Code ดักใช้ Regular Expression ช่วย โดยดักตามกลุ่ม ดังนี้

  • กลุ่ม {R[N]}
(R\d*)
  • กลุ่ม {Date หรือ Time}
[\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)
  • กลุ่ม {Interval}
P(?!$)((\d+Y)|(\d+\.\d+Y$))?((\d+M)|(\d+\.\d+M$))?((\d+W)|(\d+\.\d+W$))?((\d+D)|(\d+\.\d+D$))?(T(?=\d)((\d+H)|(\d+\.\d+H$))?((\d+M)|(\d+\.\d+M$))?(\d+(\.\d+)?S)?)?

สำหรับแบบที 1 จะได้เป็น กลุ่ม {R[N]} หรือ กลุ่ม {Date หรือ Time} หรือ กลุ่ม {Interval} โดยได้ RegEx ดังนี้

(?:R\d*)|(?:(\/[\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?))|(?:\/P(?!$)((\d+Y)|(\d+\.\d+Y$))?((\d+M)|(\d+\.\d+M$))?((\d+W)|(\d+\.\d+W$))?((\d+D)|(\d+\.\d+D$))?(T(?=\d)((\d+H)|(\d+\.\d+H$))?((\d+M)|(\d+\.\d+M$))?(\d+(\.\d+)?S)?)?)

ผมได้เขียน RegEx ไว้ ดังนี้ครับ และสำหรับ Java ผมได้ทดสอบเพิ่มเติม เนื่องจากมันจะมีข้อจุกจิเล็กน้อยของแต่ละภาษาครับ

ปรับให้มันซับซ้อนขึ้นตามข้อกำหนดที่ {R[N]}/{Interval} มาคู่กันครับ


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts sent to your email.