Brian Kernighan 與 Rob Pike 在《軟件工程實踐》中呈現了一個極精簡的正則引擎,僅支援 .、*、^、$ 四種元字符,代碼不足 50 行卻涵蓋核心匹配邏輯。本文完整呈現並逐函數解析。
| 元字符 | 含義 |
|---|---|
c | 匹配字面字符 c |
. | 匹配任意單字符 |
* | 前一字符出現 0 次或多次 |
^ | 匹配字串開頭(僅模式首位有效) |
$ | 匹配字串結尾(僅模式尾位有效) |
#include <stdio.h>
int matchhere(char *, char *);
int matchstar(int c, char *regexp, char *text) {
char *t;
for (t = text; *t != '\0' && (*t == c || c == '.'); t++);
do {
if (matchhere(regexp, t)) return 1;
} while (t-- > text);
return 0;
}
int matchhere(char *regexp, char *text) {
if (regexp[0] == '\0') return 1;
if (regexp[1] == '*') return matchstar(regexp[0], regexp + 2, text);
if (regexp[0] == '$' && regexp[1] == '\0') return *text == '\0';
if (text[0] != '\0' && (regexp[0] == '.' || regexp[0] == text[0]))
return matchhere(regexp + 1, text + 1);
return 0;
}
int match(char *regexp, char *text) {
if (regexp[0] == '^') return matchhere(regexp + 1, text);
do {
if (matchhere(regexp, text)) return 1;
} while (*text++ != '\0');
return 0;
}
int main() {
char *regexp = ".*$";
char *text = "123";
if (match(regexp, text)) puts("ok");
return 0;
}
match(regexp, text) — 入口函數^ 錨點:若模式以 ^ 開頭,僅從文本開頭匹配do-while 循環)matchhere(regexp, text) — 核心遞歸匹配* → 委派 matchstar$ 且結尾 → 檢查文本是否也結尾.) → 遞歸匹配剩餘matchstar(c, regexp, text) — 星號處理c 或 . 的字符do-while(t-- > text))match(".*$", "123")match:模式無 ^,進入循環matchhere(".*$", "123")matchhere:見 .* → matchstar('.', "$", "123")matchstar:掃描到結尾 t="\0"matchhere("$", "123") 失敗 → matchhere("$", "23") 失敗 → ... → matchhere("$", "") 成功ok+(一次或多次)、?(零或一次)[abc]、分組 (...)此實現展示了遞歸下降 + 回溯的核心思想,代碼極簡卻完整,是學習正則引擎原理的最佳入門材料。