ข้ามไปเนื้อหาหลัก

Category: reference

Regular Expressions ใน JavaScript — Pattern Matching ที่ใช้ได้จริง

Regex patterns ที่ใช้บ่อยใน JavaScript และ TypeScript รวม flags, character classes, groups, lookahead/lookbehind และ use cases จริงสำหรับ validation และ parsing

· อ่านประมาณ 3 นาที

สารบัญ

Syntax พื้นฐาน

// สร้าง regex
const pattern1 = /hello/;          // literal
const pattern2 = new RegExp('hello'); // constructor (ใช้เมื่อ dynamic)

// methods
pattern1.test('hello world');   // true — ทดสอบว่า match หรือไม่
'hello world'.match(/hello/);   // ['hello'] — หา match แรก
'hello world'.replace(/hello/, 'hi'); // 'hi world'
'a,b,,c'.split(/,+/);          // ['a', 'b', 'c'] — split ด้วย pattern

Flags

/pattern/i   // case-insensitive — ไม่สนใจตัวพิมพ์เล็ก/ใหญ่
/pattern/g   // global — หาทุก match ไม่ใช่แค่อันแรก
/pattern/m   // multiline — ^ และ $ match ต่อบรรทัด
/pattern/s   // dotAll — . match newline ด้วย
/pattern/gi  // รวมหลาย flag

'Hello WORLD'.match(/[a-z]+/gi); // ['Hello', 'WORLD']

Character Classes

\d        // digit: [0-9]
\D        // ไม่ใช่ digit
\w        // word: [a-zA-Z0-9_]
\W        // ไม่ใช่ word
\s        // whitespace (space, tab, newline)
\S        // ไม่ใช่ whitespace
.         // อักขระใดก็ได้ยกเว้น newline
[abc]     // a หรือ b หรือ c
[^abc]    // ไม่ใช่ a, b, c
[a-z]     // a ถึง z
[a-zA-Z] // ตัวอักษร English ใดก็ได้

Quantifiers

a*      // 0 ครั้งหรือมากกว่า (greedy)
a+      // 1 ครั้งหรือมากกว่า
a?      // 0 หรือ 1 ครั้ง (optional)
a{3}    // ตรงๆ 3 ครั้ง
a{2,4}  // 2 ถึง 4 ครั้ง
a{2,}   // 2 ครั้งขึ้นไป

// Non-greedy (lazy) — จับน้อยที่สุด
a*?     // 0 ครั้งหรือมากกว่า แต่จับน้อยที่สุด
a+?     // 1 ครั้งหรือมากกว่า แต่จับน้อยที่สุด

Groups และ Capturing

// Capturing group — จับ match ใว้
const match = '2026-06-14'.match(/(\d{4})-(\d{2})-(\d{2})/);
// match[0] = '2026-06-14' (full match)
// match[1] = '2026'
// match[2] = '06'
// match[3] = '14'

// Named capturing group
const { year, month, day } = '2026-06-14'.match(
  /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
)?.groups ?? {};

// Non-capturing group — จัดกลุ่มแต่ไม่จับ
/(https?):\/\//.test('https://example.com'); // http: หรือ https:

Lookahead และ Lookbehind

// Positive lookahead — X ตามด้วย Y
/\d+(?= baht)/g    // จับตัวเลขที่ตามด้วย " baht"
'100 baht 200 usd'.match(/\d+(?= baht)/g); // ['100']

// Negative lookahead — X ที่ไม่ตามด้วย Y
/\d+(?! baht)/g    // จับตัวเลขที่ไม่ตามด้วย " baht"

// Positive lookbehind — X ที่นำหน้าด้วย Y
/(?<=฿)\d+/g       // จับตัวเลขที่นำหน้าด้วย ฿
'฿100 $200'.match(/(?<=฿)\d+/g); // ['100']

Use Cases จริง

// Email validation (basic)
function isValidEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

// Thai phone number
function isThaiPhone(phone: string): boolean {
  return /^(0[689]\d{8}|0[2-7]\d{7})$/.test(phone.replace(/[-\s]/g, ''));
}

// URL slug — lowercase, hyphens เท่านั้น
function slugify(text: string): string {
  return text
    .toLowerCase()
    .replace(/[^\w\s-]/g, '')   // ลบ special chars
    .replace(/[\s_-]+/g, '-')   // เปลี่ยน spaces/underscores เป็น -
    .replace(/^-+|-+$/g, '');   // ลบ leading/trailing -
}

// Extract all URLs จาก text
function extractUrls(text: string): string[] {
  return text.match(/https?:\/\/[^\s)>"]+/g) ?? [];
}

// Strip HTML tags
function stripHtml(html: string): string {
  return html.replace(/<[^>]+>/g, '');
}

// Word count — นับคำ (ไม่รวม whitespace ต่อเนื่อง)
function countWords(text: string): number {
  return text.trim().split(/\s+/).filter(Boolean).length;
}

TypeScript กับ Regex

// RegExp type
const pattern: RegExp = /\d+/g;

// ใช้กับ matchAll สำหรับ global flag
const text = 'foo 1 bar 2 baz 3';
const matches = [...text.matchAll(/(\d+)/g)];
// matches = [['1', '1'], ['2', '2'], ['3', '3']]
// แต่ละ element เป็น array ที่มี full match และ groups

// String.prototype.replaceAll() — ง่ายกว่า /g flag ในบางกรณี
'a-b-c'.replaceAll('-', '_'); // 'a_b_c'

// Named groups กับ TypeScript (ต้อง match ก่อน)
const result = /(?<year>\d{4})/.exec('2026');
const year = result?.groups?.year; // string | undefined

ข้อควรระวัง

// ❌ Catastrophic Backtracking — regex ที่ทำให้ hang
// /^(a+)+$/ กับ input 'aaaaaab' — exponential time
// ❌ อย่าใช้ regex ที่ซ้อน quantifier แบบนี้

// ❌ RegExp constructor กับ user input
const userInput = '.+'; // user input ที่ไม่ผ่าน sanitize
new RegExp(userInput);  // ทำงานได้ แต่เสี่ยง ReDoS attack

// ✅ escape user input ก่อนนำเข้า RegExp
function escapeRegex(str: string): string {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
const safe = new RegExp(escapeRegex(userInput));