Kiểm tra Regex
Kiểm tra biểu thức chính quy với một chuỗi và xem tất cả kết quả khớp được tô sáng
Biểu thức
Chuỗi kiểm tra
Biểu thức chính quy là gì?
Biểu thức chính quy (regex hoặc regexp) là một chuỗi ký tự định nghĩa một mẫu tìm kiếm. Công cụ kiểm tra regex cho phép bạn viết một mẫu, chạy nó với văn bản mẫu và xem tất cả kết quả khớp được tô sáng theo thời gian thực. Khái niệm này bắt nguồn từ công trình của nhà toán học Stephen Kleene về ngôn ngữ chính quy vào những năm 1950, và Ken Thompson đã xây dựng engine regex đầu tiên vào trình soạn thảo văn bản QED năm 1968.
Một engine regex đọc mẫu từ trái sang phải, tiêu thụ các ký tự đầu vào khi cố khớp. Nó sử dụng backtracking khi một kết quả khớp một phần thất bại: engine lùi lại và thử các nhánh thay thế trong mẫu. Một số engine (như RE2 dùng trong Go) tránh hoàn toàn backtracking bằng cách chuyển đổi mẫu thành automata hữu hạn xác định (DFA), đảm bảo khớp theo thời gian tuyến tính nhưng không hỗ trợ các tính năng như back-reference.
Cú pháp regex được chuẩn hóa một cách lỏng lẻo. PCRE (Perl Compatible Regular Expressions) là dạng phổ biến nhất, được hỗ trợ bởi PHP, module re của Python và JavaScript với một số khác biệt nhỏ. POSIX định nghĩa một cú pháp hạn chế hơn được dùng bởi grep và sed. Những khác biệt này quan trọng khi chuyển mẫu giữa các ngôn ngữ: một lookahead hoạt động trong JavaScript có thể không biên dịch được trong engine RE2 của Go.
Tại sao dùng công cụ kiểm tra Regex trực tuyến?
Viết regex trong file code đòi hỏi phải lưu, chạy và kiểm tra kết quả mỗi lần bạn điều chỉnh mẫu. Một công cụ kiểm tra regex trên trình duyệt rút ngắn vòng phản hồi đó về zero: bạn gõ, bạn thấy kết quả khớp.
Các trường hợp sử dụng công cụ kiểm tra Regex
Tham chiếu nhanh cú pháp Regex
Bảng dưới đây bao gồm các token regex được dùng nhiều nhất. Chúng hoạt động trên JavaScript, Python, Go, PHP và hầu hết các engine tương thích PCRE. Các extension theo ngôn ngữ (như conditional pattern của Python hoặc named group của JavaScript với cú pháp \k) được ghi chú trong phần ví dụ mã.
| Mẫu | Tên | Mô tả |
|---|---|---|
| . | Any character | Matches any single character except newline (unless s flag is set) |
| \d | Digit | Matches [0-9] |
| \w | Word character | Matches [a-zA-Z0-9_] |
| \s | Whitespace | Matches space, tab, newline, carriage return, form feed |
| \b | Word boundary | Matches the position between a word character and a non-word character |
| ^ | Start of string/line | Matches the start of the input; with m flag, matches start of each line |
| $ | End of string/line | Matches the end of the input; with m flag, matches end of each line |
| * | Zero or more | Matches the preceding token 0 or more times (greedy) |
| + | One or more | Matches the preceding token 1 or more times (greedy) |
| ? | Optional | Matches the preceding token 0 or 1 time |
| {n,m} | Quantifier range | Matches the preceding token between n and m times |
| () | Capturing group | Groups tokens and captures the matched text for back-references |
| (?:) | Non-capturing group | Groups tokens without capturing the matched text |
| (?=) | Positive lookahead | Matches a position followed by the given pattern, without consuming it |
| (?<=) | Positive lookbehind | Matches a position preceded by the given pattern, without consuming it |
| [abc] | Character class | Matches any one of the characters inside the brackets |
| [^abc] | Negated class | Matches any character not inside the brackets |
| | | Alternation | Matches the expression before or after the pipe |
Giải thích các cờ Regex
Cờ (còn gọi là modifier) thay đổi cách engine xử lý mẫu. Trong JavaScript bạn thêm chúng sau dấu gạch chéo đóng: /pattern/gi. Trong Python bạn truyền chúng làm đối số thứ hai: re.findall(pattern, text, re.IGNORECASE | re.MULTILINE). Không phải tất cả cờ đều có sẵn trong mọi ngôn ngữ.
| Cờ | Tên | Hành vi |
|---|---|---|
| g | Global | Find all matches, not just the first one |
| i | Case-insensitive | Letters match both uppercase and lowercase |
| m | Multiline | ^ and $ match start/end of each line, not just the whole string |
| s | Dot-all | . matches newline characters as well |
| u | Unicode | Treat the pattern and subject as a Unicode string; enables \u{FFFF} syntax |
| y | Sticky | Matches only from the lastIndex position in the target string |
Ví dụ mã
Các ví dụ regex thực tế trong JavaScript, Python, Go và dòng lệnh. Mỗi ví dụ minh họa cách xây dựng mẫu, trích xuất kết quả khớp và đầu ra.
// Match all email addresses in a string
const text = 'Contact us at support@example.com or sales@example.com'
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
const matches = text.matchAll(emailRegex)
for (const match of matches) {
console.log(match[0], 'at index', match.index)
}
// → "support@example.com" at index 14
// → "sales@example.com" at index 37
// Named capture groups (ES2018+)
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const result = '2026-03-30'.match(dateRegex)
console.log(result.groups)
// → { year: "2026", month: "03", day: "30" }
// Replace with a callback
'hello world'.replace(/\b\w/g, c => c.toUpperCase())
// → "Hello World"import re
# Find all IPv4 addresses
text = 'Server 192.168.1.1 responded, fallback to 10.0.0.255'
pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
matches = re.findall(pattern, text)
print(matches) # → ['192.168.1.1', '10.0.0.255']
# Named groups and match objects
date_pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
m = re.search(date_pattern, 'Released on 2026-03-30')
if m:
print(m.group('year')) # → '2026'
print(m.group('month')) # → '03'
# Compile for repeated use (faster in loops)
compiled = re.compile(r'\b[A-Z][a-z]+\b')
words = compiled.findall('Hello World Foo bar')
print(words) # → ['Hello', 'World', 'Foo']package main
import (
"fmt"
"regexp"
)
func main() {
// Find all matches
re := regexp.MustCompile(`\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b`)
text := "Contact support@example.com or sales@example.com"
matches := re.FindAllString(text, -1)
fmt.Println(matches)
// → [support@example.com sales@example.com]
// Named capture groups
dateRe := regexp.MustCompile(`(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})`)
match := dateRe.FindStringSubmatch("2026-03-30")
for i, name := range dateRe.SubexpNames() {
if name != "" {
fmt.Printf("%s: %s\n", name, match[i])
}
}
// → year: 2026
// → month: 03
// → day: 30
// Replace with a function
result := re.ReplaceAllStringFunc(text, func(s string) string {
return "[REDACTED]"
})
fmt.Println(result)
// → Contact [REDACTED] or [REDACTED]
}# Find lines matching an IP address pattern
grep -E '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' access.log
# Extract email addresses from a file
grep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' contacts.txt
# Replace dates from YYYY-MM-DD to DD/MM/YYYY using sed
echo "2026-03-30" | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/'
# → 30/03/2026
# Count matches per file in a directory
grep -rcE 'TODO|FIXME|HACK' src/
# → src/main.js:3
# → src/utils.js:1