网站首页 > 技术文章 正文
以下是C语言实现正则表达式的代码:
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
bool isMatch(char* s, char* p) {
int m = strlen(s);
int n = strlen(p);
// 检查模式p的合法性,避免无效的'*'
for (int i = 0; i < n; ++i) {
if (p[i] == '*' && (i == 0 || p[i-1] == '*')) {
return false;
}
}
// 创建动态规划表,dp[i][j]表示s的前i个字符和p的前j个字符是否匹配
bool *dp = (bool *)calloc((m+1) * (n+1), sizeof(bool));
if (!dp) {
return false; // 内存分配失败,但题目通常保证不会出现
}
// 初始化基础情况:空字符串匹配空模式
dp[0] = true;
// 初始化第一行,处理模式p可以匹配空字符串的情况(如"a*")
for (int j = 1; j <= n; ++j) {
if (p[j-1] == '*') {
dp[j] = dp[j-2]; // 匹配0次的情况
}
}
// 填充dp表
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j-1] == '*') {
// 处理'*'的情况,考虑匹配0次或多次
bool matchZero = dp[i*(n+1) + (j-2)];
bool matchMore = (p[j-2] == '.' || s[i-1] == p[j-2]) && dp[(i-1)*(n+1) + j];
dp[i*(n+1)+j] = matchZero || matchMore;
} else {
// 处理普通字符或'.'的情况
bool currentMatch = (p[j-1] == '.' || s[i-1] == p[j-1]);
dp[i*(n+1)+j] = currentMatch && dp[(i-1)*(n+1) + (j-1)];
}
}
}
bool result = dp[m*(n+1) + n];
free(dp);
return result;
}
void test(const char *s, const char *p, bool expected) {
bool result = isMatch((char*)s, (char*)p);
printf("s=\"%s\", p=\"%s\" -> %s (Expected %s)\n",
s, p,
result ? "true" : "false",
expected ? "true" : "false");
}
int main() {
// 完全匹配
test("aa", "aa", true);
// '.' 匹配任意字符
test("ab", "a.", true);
// '*' 匹配零次
test("a", "ab*", true); // b* 匹配零次
// '*' 匹配多次
test("aaa", "a*", true); // a* 匹配三次
test("ab", "a*b", true); // a* 匹配一次
// 复杂组合
test("aab", "c*a*b", true); // c* 匹配零次,a* 匹配两次
test("mississippi", "mis*is*p*.", false); // 无法匹配
// 无效模式
test("a", "a**", false); // 连续 '*' 非法
// 空字符串
test("", "", true); // 空字符串匹配空模式
test("", "a*", true); // a* 匹配零次
// 边界情况
test("a", ".*", true); // .* 匹配任意字符
return 0;
}
代码解析
- 合法性检查
确保模式 p 中的 * 不连续且不位于开头。例如 a** 或 *a 是非法的。 - 动态规划表初始化
- 使用 calloc 分配 (m+1)*(n+1) 的布尔数组,初始值为 false。
- dp[i][j] 表示 s 的前 i 个字符与 p 的前 j 个字符是否匹配。
- 基础情况
- dp[0][0] = true:空字符串与空模式匹配。
- 第一行处理模式 p 匹配空字符串的情况(例如 a* 可以匹配空)。
- 填充表格
当 p[j-1] 是 * 时:
- matchZero:匹配零次(跳过 p[j-2]),即 dp[i][j-2]。
- matchMore:匹配多次(需 p[j-2] 与 s[i-1] 匹配),即 dp[i-1][j]。
- 普通字符或 .:直接检查当前字符是否匹配,并依赖 dp[i-1][j-1]。
- 结果提取与内存释放
最终结果存储在 dp[m][n] 中,释放动态规划表内存。
算法复杂度
- 时间复杂度:O(m*n),需填充 m*n 的表格。
- 空间复杂度:O(m*n),使用一维数组模拟二维表。
- 上一篇: C语言解决荷兰国旗问题
- 下一篇: 编写第一个C++程序-HelloWorld示例
猜你喜欢
- 2025-04-24 从零开始学习C语言丨参数的传递方式
- 2025-04-24 C语言 | 成绩的等级判别
- 2025-04-24 C语言随机数生成
- 2025-04-24 C语言-平方倒数和
- 2025-04-24 C语言100题集合019-实现输入一个星期中对应的第几天
- 2025-04-24 编写第一个C++程序-HelloWorld示例
- 2025-04-24 C语言解决荷兰国旗问题
- 2025-04-24 C语言求两个数的最大公约数,最小公倍数
- 2025-04-24 C语言实现最长公共前缀
- 2024-07-18 C 语言——运算符基础知识浅析(c语言 |运算符)
- 04-24架构篇-一分钟掌握性能优化小技巧
- 04-24Nginx从概念到实战:原理、配置与踩坑全解析
- 04-24前端面试题-Vue 项目中,你做过哪些性能优化?
- 04-24从零开始学习C语言丨参数的传递方式
- 04-24C语言 | 成绩的等级判别
- 04-24C语言随机数生成
- 04-24C语言-平方倒数和
- 04-24C语言100题集合019-实现输入一个星期中对应的第几天
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)