用C实现一个最简单的正则表达式引擎

news2025/4/7 5:31:57

用C实现一个简单的正则表达式引擎

下面我将实现一个极简的正则表达式引擎,仅支持以下基本功能:

  • . 匹配任意单个字符
  • * 匹配零个或多个前导字符
  • ^ 匹配字符串开头
  • $ 匹配字符串结尾

完整代码实现

#include <stdio.h>
#include <stdbool.h>

bool match_here(const char *regexp, const char *text);
bool match_star(char c, const char *regexp, const char *text);

/* 正则表达式匹配入口函数 */
bool regex_match(const char *regexp, const char *text) {
    // 处理 ^ 开头的情况
    if (regexp[0] == '^') {
        return match_here(regexp + 1, text);
    }
    
    // 尝试在文本的每个位置匹配
    do {
        if (match_here(regexp, text)) {
            return true;
        }
    } while (*text++ != '\0');
    
    return false;
}

/* 在当前位置尝试匹配 */
bool match_here(const char *regexp, const char *text) {
    // 正则表达式已结束,匹配成功
    if (regexp[0] == '\0') {
        return true;
    }
    
    // 处理 $ 结尾的情况
    if (regexp[0] == '$' && regexp[1] == '\0') {
        return *text == '\0';
    }
    
    // 处理 * 量词
    if (regexp[1] == '*') {
        return match_star(regexp[0], regexp + 2, text);
    }
    
    // 处理 . 通配符或普通字符匹配
    if (*text != '\0' && (regexp[0] == '.' || regexp[0] == *text)) {
        return match_here(regexp + 1, text + 1);
    }
    
    return false;
}

/* 处理 * 量词匹配 */
bool match_star(char c, const char *regexp, const char *text) {
    do {
        // 尝试匹配剩余部分
        if (match_here(regexp, text)) {
            return true;
        }
    } while (*text != '\0' && (*text++ == c || c == '.'));
    
    return false;
}

/* 测试函数 */
int main() {
    const char *tests[][2] = {
        {"a", "a"},             // 匹配
        {"a", "b"},             // 不匹配
        {"a*", ""},             // 匹配
        {"a*", "aaaaa"},        // 匹配
        {".*", "anything"},     // 匹配
        {"^a", "a"},            // 匹配
        {"^a", "ba"},           // 不匹配
        {"a$", "a"},            // 匹配
        {"a$", "ab"},           // 不匹配
        {"a*b", "aaaab"},       // 匹配
        {"a*b", "b"},           // 匹配
        {"a*b", "aaaac"},       // 不匹配
        {NULL, NULL}
    };
    
    for (int i = 0; tests[i][0] != NULL; i++) {
        bool result = regex_match(tests[i][0], tests[i][1]);
        printf("'%s' matches '%s': %s\n", 
               tests[i][0], tests[i][1], result ? "true" : "false");
    }
    
    return 0;
}

实现解析

  1. 核心函数

    • regex_match(): 入口函数,处理 ^ 开头的情况
    • match_here(): 在当前位置尝试匹配
    • match_star(): 专门处理 * 量词匹配
  2. 匹配逻辑

    • 普通字符:必须精确匹配
    • .:匹配任意单个字符
    • *:匹配前导字符零次或多次(贪婪匹配)
    • ^:必须从字符串开头匹配
    • $:必须匹配到字符串结尾
  3. 递归实现

    • 通过递归调用实现模式匹配
    • 遇到 * 时尝试所有可能的匹配长度

扩展建议

这个简单引擎可以进一步扩展:

  1. 添加 +(一次或多次)和 ?(零次或一次)量词
  2. 支持字符类 [a-z]
  3. 实现转义字符 \
  4. 添加分组捕获功能

这个实现参考了Rob Pike在《The Practice of Programming》中介绍的正则表达式引擎设计,是一个非常精简但完整的实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2328726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

哈密尔顿路径(Hamiltonian Path)及相关算法题目

哈密尔顿路径要求访问图中每个顶点恰好一次&#xff0c;通常用于解决旅行商问题&#xff08;TSP&#xff09;或状态压缩DP问题。 哈密尔顿路径&#xff08;Hamiltonian Path&#xff09;是指在一个图中经过每个顶点恰好一次的路径。如果这条路径的起点和终点相同&#xff08;即…

MINIQMT学习课程Day10

开始获取股票数据课程的学习&#xff1a; 获取qmt账号的持仓情况后&#xff0c;我们进入下一步&#xff0c;如何获得当前账号的委托状况 还是之前的步骤&#xff0c;打开qmt&#xff0c;选择独立交易&#xff0c; 之后使用pycharm&#xff0c;编写py文件 导入包&#xff1a…

JAVA实战开源项目:智慧图书管理系统(Vue+SpringBoot) 附源码

本文项目编号 T 152 &#xff0c;文末自助获取源码 \color{red}{T152&#xff0c;文末自助获取源码} T152&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

Linux 系统管理综合实训 —— 基于 NAT 模式的多 IP 配置、Nginx 服务部署及存储管理

1. 虚拟机网络配置&#xff1a;NAT模式与多IP地址设置 将你的虚拟机的网卡模式设置为nat模式&#xff0c;给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 设置静态IP [rootlocalhost ~]# nmcli c modify ens160 ipv4.method manual ipv4.addresses 192.168.2.100/2…

如何在windows 环境、且没有显卡的情况下用python跑通从ModelScope下载的大模型的调用

文章目录 背景介绍源代码&#xff1a;安装调试过程1.设置第三方镜像源2.预先安装&#xff1a;3.在python中创建代码&#xff1a;4.最终修改程序,将device_map从“cuda”改成“auto”&#xff0c;大模型调用1.5B&#xff08;1___5B)的5.最终跑出结果解释&#xff1a;示例&#x…

黑马点评redis改 part 1

本篇将主要阐述短信登录的相关知识&#xff0c;感谢黑马程序员开源&#xff0c;感谢提供初始源文件&#xff08;给到的是实战第7集开始的代码&#xff09;【Redis实战篇】黑马点评学习笔记&#xff08;16万字超详细、Redis实战项目学习必看、欢迎点赞⭐收藏&#xff09;-CSDN博…

【Ragflow】11. 文件解析流程分析/批量解析实现

概述 本文继续对ragflow文档解析部分进行分析&#xff0c;并通过脚本的方式实现对文件的批量上传解析。 文件解析流程 文件解析的请求处理流程大致如下&#xff1a; 1.前端上传文件&#xff0c;通过v1/document/run接口&#xff0c;发起文件解析请求 2.后端api\apps\docum…

第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

✨前言&#xff1a;传参和状态管理&#xff0c;看似简单其实门道不少 在 Web 开发中&#xff0c;前端和后端最核心的交流方式就是“传参”&#xff0c;而“传参”除了涉及如何写代码获取参数&#xff0c;还藏着很多开发者容易忽略的细节&#xff1a; 为什么 URL 带了中文&…

Everything 安装教程与使用教程(附安装包)

文章目录 前言一、Everything 介绍二、Everything 安装教程1.Everything 安装包下载2.选择安装文件3.选择安装语言4.接受许可协议5.选择安装位置6.配置安装选项7.完成安装 三、Everything 使用教程1.启动软件2.简单关键词搜索3.按类型搜索 前言 在日常使用电脑时&#xff0c;随…

SQL语句(三)—— DQL

目录 基本语法 一、基础查询 1、查询多个字段 2、字段设置别名 3、去除重复记录 4、示例代码 二、条件查询 1、语法 2、条件列表常用的运算符 3、示例代码 三、分组查询 &#xff08;一&#xff09;聚合函数 1、介绍 2、常见的聚合函数 3、语法 4、示例代码 &…

Opencv计算机视觉编程攻略-第九节 描述和匹配兴趣点

一般而言&#xff0c;如果一个物体在一幅图像中被检测到关键点&#xff0c;那么同一个物体在其他图像中也会检测到同一个关键点。图像匹配是关键点的常用功能之一&#xff0c;它的作用包括关联同一场景的两幅图像、检测图像中事物的发生地点等等。 1.局部模板匹配 凭单个像素就…

汇编学习之《push , pop指令》

学习本章前线了解ESP, EBP 指令 汇编学习之《指针寄存器&大小端学习》-CSDN博客 栈的特点&#xff1a; 好比一个垂直容器&#xff0c;可以陆续放入物体&#xff0c;但是先放的物体通常会被后面放的物体压着&#xff0c;只有等上面后放的物品拿出来后&#xff0c;才能…

Python循环控制语句

1. 循环类型概述 Python提供两种主要的循环结构&#xff1a; while循环 - 在条件为真时重复执行for循环 - 遍历序列中的元素 2. while循环 基本语法 while 条件表达式:循环体代码示例 count 0 while count < 5:print(f"这是第{count1}次循环")count 13. f…

微信小程序(下)

目录 在事件处理函数中为 data 中的数据赋值 事件传参 bindinput 的语法格式 实现文本框和 data 之间的数据同步 条件渲染 结合 使用 wx:if hidden wx:if与 hidden 的对比 wx:for 手动指定索引和当前项的变量名 wx:key 的使用 WXSS 和 CSS 的关系 什么是 rpx 尺寸…

【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍

考虑到每个人基础可能不一样&#xff0c;且并不是所有人都有同时做2D、3D开发的需求&#xff0c;所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要讲解C#的基础语法&#xff0c;包括变量、数据类型、运算符、…

vector的介绍与代码演示

由于以后我们写OJ题时会经常使用到vector&#xff0c;所以我们必不可缺的是熟悉它的各个接口。来为我们未来作铺垫。 首先&#xff0c;我们了解一下&#xff1a; https://cplusplus.com/reference/vector/ vector的概念&#xff1a; 1. vector是表示可变大小数组的序列容器…

ubuntu 22.04 解决LXC 报错CGroupV1 host system

解决CGroupV1 host system 报错 echo "cgroupv1 environment" sed -i s/^GRUB_CMDLINE_LINUX.*/GRUB_CMDLINE_LINUX_DEFAULT"quiet splash systemd.unified_cgroup_hierarchy0" / /etc/default/grub update-grub reboot 下载oracle 7 Linux 容器测试 l…

JavaEE初阶复习(JVM篇)

JVM Java虚拟机 jdk java开发工具包 jre java运行时环境 jvm java虚拟机(解释执行 java 字节码) java作为一个半解释,半编译的语言,可以做到跨平台. java 通过javac把.java文件>.class文件(字节码文件) 字节码文件, 包含的就是java字节码, jvm把字节码进行翻译转化为…

MINIQMT学习课程Day9

获取qmt账号的持仓情况后&#xff0c;我们进入下一步&#xff0c;如何获得当前账号的委托状况 还是之前的步骤&#xff0c;打开qmt&#xff0c;选择独立交易&#xff0c; 之后使用pycharm&#xff0c;编写py文件 导入包&#xff1a; from xtquant import xtdata from xtqua…

动态规划似包非包系列一>组合总和IIV

目录 题目分析&#xff1a;状态表示&#xff1a;状态转移方程&#xff1a;初始化填表顺序返回值&#xff1a;代码呈现&#xff1a; 题目分析&#xff1a; 状态表示&#xff1a; 状态转移方程&#xff1a; 初始化填表顺序返回值&#xff1a; 代码呈现&#xff1a; class Soluti…