简介这份课程设计报告面向计算机科学与技术等专业学生聚焦编译原理中有限自动机空闭包ε-closureI的程序实现帮助读者理解并动手完成从NFA输入到状态子集构造的完整流程。报告以Java为实现语言内容覆盖需求分析、概要设计、详细设计、测试与分析、用户使用说明及总结并附程序源代码核心算法包括对初态节点X读空、对状态子集读空、对状态子集读字母表以及递归累积结果求空闭包同时以状态转换图方式展示自动机要求节点布局合理且具通用性。资源包共1个docx文件约177KB即课程设计报告正文与附录源码结构完整、便于对照阅读。目前已有1287人学习下载适合需要完成同类课程设计、准备编译原理实验或想深入掌握ε-closure计算与状态子集构造的读者参考借鉴。1. 从一条空弧说起为什么 ε-closure 值得单独做一次课程设计编译原理课上学到 NFA 转 DFA 那一章很多人第一反应是子集构造法的表格填起来挺机械真正动手写代码才发现卡住的地方根本不在主循环而在一个看起来最不起眼的操作给定一个状态子集 I把它经过任意条 ε 弧能到达的状态全部收进来也就是求 ε-closure(I)。这个操作写不对后面读字母表、扩展新状态子集全是连锁翻车。这份课程设计报告把 ε-closure(I) 的程序实现单独拎出来做一个完整课题输入任意 NFA、输出所有状态子集的空闭包、支持指定子集查询还要把自动机画成状态转换图需求边界清楚正好适合作为一份可交付的课程设计报告来拆解。它面向的是要交编译原理课设的计算机专业学生也适合想补一遍子集构造底层实现的从业者下面按需求、设计、实现、避坑、验收的顺序把整套方案讲透。2. 需求分析与技术选型四个硬指标决定程序骨架2.1 把课程设计报告里的功能要求翻译成可验收条目原始需求写了四条基本要求但直接照着写代码容易漏掉隐含约束。我一般会把它们翻译成能逐条打勾的验收条目第一NFA 要能从文件读入并保存意味着状态集、字母表、状态转移函数三部分要有明确的文本格式不能靠控制台一行行手敲第二输出所有状态子集的空闭包注意这里的主语是“所有状态子集”不是只输出初始子集所以程序内部必须先完成子集构造把可达状态子集全部枚举出来第三支持给定状态子集 I 的单独查询这一条要求查询入口和批量输出共用同一套读空逻辑否则两处结果对不上就是血泪经验第四以状态转换图方式输出自动机节点大小和位置要合理、具备通用性意思是不能针对某一个样例硬编码坐标得按状态数量和转移关系自动布局。这四条里最容易低估的是第二条。很多同学以为求 ε-closure 就是一个递归函数的事实际上“所有状态子集”要求你先有一个子集构造的闭环从新初态 X 的闭包出发对每个已得子集读字母表里每个字符再对结果读空得到新子集反复直到不再产生新子集。这个闭环没搭起来第二条要求根本交不了差。所以需求分析阶段就要明确本程序的核心不是单个函数而是“读空 读字母 子集扩展”三个动作串成的流水线。2.2 数据结构选型数组、哈希表、图各管一段报告里写的数据结构是数组、图以及哈希表这个组合不是随便凑的各自有明确分工。状态转移函数用字符串数组存最直接每条产生式形如(1,a)→3固定字符位置就能取出源状态、输入符号、目标状态解析成本极低适合课程设计这种规模。状态子集用SetString存天然去重避免同一个状态被重复加入闭包导致结果里出现重复项。所有状态子集用一个MapSetString, SetString组织键是子集本身值是它的空闭包这样批量输出和单点查询都能直接命中。数据对象选用结构理由状态转移函数String[]产生式数组格式固定按下标取字段解析快单个状态子集SetString自动去重闭包累加不会重复子集到闭包的映射HashMap批量输出与查询共用一份结果状态转换图邻接关系 布局坐标按转移关系自动算位置保证通用性这里有个选型细节值得说清楚为什么不用List存子集。读空过程中同一个状态可能通过多条空弧路径被多次到达用List就得每次contains判断代码又长又容易漏Set把去重交给容器递归累加时只管add逻辑干净很多。哈希表的选择也是同理子集作为键需要能比较相等Set的equals语义正好符合“状态集合相同即同一个子集”的定义。2.3 模块划分与调用关系报告把程序拆成前端数据传入、后台数据处理与分析、对新引入初态节点 X 的读空、对状态子集读空、对状态子集读字母表、子集扩展六个模块。这个划分的关键在于把“读空”拆成了两个函数一个专门处理新初态 X它只有空弧不需要考虑字母另一个处理普通状态子集读字母之后的结果。拆开的好处是每个函数职责单一递归终止条件清晰调试时能单独喂参数验证。调用关系是一条单向链前端解析文件得到产生式数组和字母表后台先调 X 读空拿到第一个状态子集然后进入子集扩展循环循环体内对当前子集调读字母表函数把结果再喂给状态子集读空函数得到新子集后判断是否已存在不存在就加入待处理队列。整条链上没有任何回环调用除了读空函数内部的递归。这种结构在课程设计规模下足够稳也方便在报告里画清楚模块图。3. 总体架构与核心算法设计三个函数撑起子集构造3.1 引入 X、Y 两个虚拟节点统一处理初态和终态原始 NFA 可能有多个初态也可能有多个终态直接求闭包会让边界判断变得零碎。标准做法是引入一个新的初态 X 和新的终态 YX 通过 ε 弧连到所有原初态所有原终态通过 ε 弧连到 Y。这样整个自动机变成单初态单终态后续子集构造从 X 的闭包出发即可不用再特判“哪些是初态”。报告里提到一个实现上的取舍原本想严格按“X 连到任意非空初态”来写后来发现处理起来太麻烦最终把 X 到某个固定节点的空弧直接作为一条产生式写进状态转移函数里。这个做法在课程设计场景下可以接受因为只要保证 X 的闭包能覆盖到原初态集合子集构造的起点就是对的。需要提醒的是如果原 NFA 有多个初态这条固定产生式必须确保 X 能间接到达每一个初态否则会漏状态子集。我一般会在解析阶段检查一遍X 的闭包是否包含全部原初态不包含就报错提示输入有问题这比运行到一半发现结果少了几个子集要好排查得多。3.2 读空函数的递归设计与静态变量累加对新初态 X 读空是整个流程的第一步它的逻辑是先把自身加入结果然后沿着所有 ε 弧不断扩展直到没有新状态可加。报告用递归实现每次调用处理一条产生式把新到达的状态拼到字符串上再把拼接后的字符串作为参数递归下去。这里用静态字符串变量接收累加结果是因为递归每层只能返回一个值而闭包需要累积多个状态。// 对新引入初态 X 读空沿 ε 弧递归扩展结果累加到静态字符串 public static String RestltList(String string, String[] strings) { for (int i 0; i strings.length; i) { // 产生式第 2 位是源状态与当前串末位状态比较 if (String.valueOf(string.charAt(string.length() - 1)) .equals(String.valueOf(strings[i].charAt(1)))) { // 第 4 位是输入符号等于 ε 才继续扩展 if (ε.equals(String.valueOf(strings[i].charAt(3)))) { string String.valueOf(strings[i].charAt(6)); // 第 7 位是目标状态 RestltList(string, strings); // 递归处理新加入的状态 } } } return string; }这段代码的关键参数含义string是当前已累积的状态串strings是全部产生式。判断源状态时取当前串的最后一位是因为每次扩展都把新状态追加到末尾末位就是本轮待扩展的状态。递归没有显式终止条件靠的是“没有新的 ε 产生式可匹配”自然结束。这里有个隐患如果 NFA 里存在 ε 环递归会不会无限下去因为结果串在不断变长而状态集合是有限的当所有可达状态都已在串里时虽然还会重复匹配产生式但追加的字符会让串继续变长严格说这个写法依赖状态数量有限且不会重复扩展同一状态——实际运行时如果 ε 环上的状态已经全在串里继续递归只会让串膨胀。稳妥的做法是在追加前判断目标状态是否已在串中已存在就跳过。报告里的样例规模小没暴露这个问题但作为可交付方案这个判断应该补上。3.3 读字母表函数只做纯字符转移不碰空弧读字母表函数的职责被刻意收窄给定一个状态子集和一个字母 a只找出子集里每个状态经过 a 弧直接到达的状态完全不考虑空弧。这样设计是为了让“读 a”和“读空”两个动作解耦组合顺序由上层控制。// 对状态子集读字母 a只取 a 弧直达状态不处理 ε public static String RestltListA(String string, String s, String[] strings) { String resultA ; for (int i 0; i strings.length; i) { // 产生式源状态与传入状态相同 if (string.equals(String.valueOf(strings[i].charAt(1)))) { // 产生式输入符号与待读字母相同 if (s.equals(String.valueOf(strings[i].charAt(3)))) { resultA String.valueOf(strings[i].charAt(6)); } } } return resultA; }参数string是单个状态s是待读字母strings是产生式数组。注意这个函数一次只处理一个状态上层需要对子集里每个状态分别调用再把结果合并。返回的是拼接字符串可能含重复状态交给后续读空函数用Set去重。这种“单状态、单字母、纯字符转移”的窄接口让函数极易单元测试喂一个状态和一个字母肉眼就能核对结果对不对。3.4 子集读空函数把读 a 的结果再走一遍空弧子集读空函数接收的是“读 a 之后得到的状态串”对串里每个状态检查是否还有 ε 弧可走有就继续扩展。它和 3.2 的 X 读空在逻辑上相似区别在于入参是多个状态组成的串需要外层循环遍历每个字符。// 对读 a 的结果读空遍历每个状态沿 ε 弧继续扩展 public static String DuKong(String result, String[] strings) { for (int i 0; i result.length(); i) { for (int j 0; j strings.length; j) { if (String.valueOf(result.charAt(i)) .equals(String.valueOf(strings[j].charAt(1)))) { if (ε.equals(String.valueOf(strings[j].charAt(3)))) { result String.valueOf(strings[j].charAt(6)); RestltList(result, strings); // 复用单状态读空继续扩展 } } } } return result; }这里有个容易看漏的点外层for的边界是result.length()而循环体内result在变长所以新追加的状态也会被后续迭代覆盖到相当于边遍历边扩展。这种写法能工作但可读性一般调试时容易看花眼。更清晰的做法是用一个队列存待处理状态取出一个扩展一个新状态入队直到队列空。课程设计报告里用双层循环能跑通样例但如果要作为可复用方案队列版本更值得推荐原因在避坑章节会展开。3.5 子集扩展主循环读空、读字母、再读空把前面三个函数串起来就是子集构造的主循环。从 X 的闭包作为第一个子集开始对每个待处理子集、字母表里每个字母执行“读 a → 读空”得到候选新子集若不在已有集合中就加入待处理队列。报告里主函数对allset2遍历对每个子集再遍历其状态逐个调读空函数把结果放进mapmax最后统一输出“状态子集 状态子集空闭包”的对照表。// 批量求所有状态子集的空闭包并输出 MapSetString, SetString mapmax new HashMap(); for (EntrySetString, SetString entry : allset2) { SetString key entry.getKey(); SetString closure new HashSet(); for (String state : key) { if (.equals(state)) break; closure.add(state); // 闭包先包含自身 String[] expanded Utils.stringtoStringArray( Utils.RestltList(state, functionStrings)); for (String s : expanded) closure.add(s); // 再加入读空结果 } mapmax.put(key, closure); } System.out.println(状态子集状态子集空闭包); for (EntrySetString, SetString e : mapmax.entrySet()) { System.out.println(e.getKey() e.getValue()); }这段代码体现了“闭包先含自身”这个定义要点ε-closure(I) 一定包含 I 本身再并上所有经 ε 弧可达的状态。输出格式用分隔子集和闭包方便肉眼比对。参数上allset2是子集构造阶段产出的全部可达子集functionStrings是产生式数组。整个主循环没有再做子集扩展因为扩展已在前面完成这里只负责给每个子集配一个闭包职责分离得很清楚。4. 状态转换图与输入格式让程序能通用地跑起来4.1 输入文件格式约定程序要求 NFA 从文件读入并保存格式必须固定才能解析。报告样例里第一行是状态集第二行是字母表之后每行一条产生式形如(X,ε)→5、(5,a)→5。这种格式的好处是人和程序都能读缺点是字段位置固定一旦多一个空格解析就错位。我一般会在解析前先做一次清洗去掉所有空白字符再按括号、逗号、箭头切分而不是依赖固定下标取字符。固定下标在样例上跑得飞快换个输入格式就翻车这是课程设计里最常见的返工点之一。保存功能同理输出时按同样格式写回文件保证“读进来—存出去—再读进来”结果一致。这个往返测试是验收时很好用的一招能顺带验证解析和序列化两边是否对称。4.2 状态转换图的自动布局思路状态转换图要求节点大小位置合理、具备通用性意味着不能手写坐标。通常的做法是先统计状态数量 n把节点均匀分布在一个圆周上圆心取画布中心半径按 n 调整n 大半径大避免节点挤在一起。转移边用带箭头的线连接源节点和目标节点自环画在节点上方的小弧双向边稍微错开避免重叠。节点标签用状态名ε 边可以加虚线或标注 ε 区分。布局算法本身不复杂难点在于边的避让。课程设计规模下圆周布局加简单错位基本够用如果状态多、边密集可以按源状态分组同组出边按角度排序再分配减少交叉。报告里强调“通用性”本质就是布局参数全部由状态数和转移关系算出不出现任何针对特定样例的硬编码坐标。验收时可以拿三个不同规模的 NFA 各画一次看节点是否重叠、边是否穿过节点能过这三关基本就达标了。4.3 单点查询与批量输出共用一套逻辑需求第三条要求输出给定状态子集的空闭包这条如果单独写一套读空代码很容易和批量输出结果不一致。正确做法是查询入口只做一件事把用户输入的状态子集解析成Set然后调用和批量输出完全相同的读空函数结果直接返回。这样两处结果天然一致测试时也只需要验证一套逻辑。报告里主函数对每个子集逐个状态调RestltList再合并查询时复用同一个函数即可不需要另起炉灶。5. 避坑与常见问题排查五个最容易翻车的点5.1 现象输出闭包里状态重复出现原因用字符串拼接却忘了去重解决统一用 Set 收口读空函数返回的是拼接字符串如果直接把字符串当结果输出同一个状态经多条空弧到达就会重复。更隐蔽的是重复会让后续子集比较失效——两个内容相同的子集因为字符串顺序或重复不同被判成不同子集子集构造就停不下来。解决方式是在每个对外输出或比较的边界把字符串转成Set去重交给容器。我一般会在读空函数外面包一层转换内部递归仍用字符串图方便出口一律Set。5.2 现象程序在含 ε 环的 NFA 上卡死或栈溢出原因递归没有“已访问”判断解决扩展前检查目标状态是否已在结果中3.2 节提到的递归写法在 ε 环上会反复扩展同一批状态。现象是控制台长时间无输出或者直接抛栈溢出。根因是递归只判断“有没有匹配的 ε 产生式”没判断“这个状态是不是已经收过了”。解决很简单追加目标状态前先检查它是否已在当前结果串里在就跳过。更彻底的做法是把递归改成显式栈或队列配一个visited集合逻辑更可控也方便在报告里画流程图。5.3 现象子集构造少了很多子集原因读 a 之后忘了再读空解决严格执行“读空—读 a—读空”顺序这是最典型的逻辑翻车。只读 a 不读空会漏掉“经 a 到达某状态后再经 ε 弧能到的状态”导致新子集偏小后续扩展自然缺枝少叶。报告总结里也专门提到这一点读 a 前后都要考虑读空。落地时建议把顺序写死成一个组合函数moveThenClosure(subset, a)内部先对子集读 a再对结果读空调用方不用关心顺序减少写错的可能。5.4 现象换一个 NFA 输入就解析报错或结果错乱原因产生式解析依赖固定字符下标解决先清洗空白再按分隔符切分样例产生式(1,a)→3里每个字段位置固定用charAt(1)、charAt(3)、charAt(6)取值在样例上没问题。但输入里多一个空格、状态名变成两位数下标全错。现象是解析出的源状态或目标状态莫名其妙甚至数组越界。解决方式是解析阶段先去掉所有空白再用正则或split按(、,、)、→切分字段按语义取而不是按位置取。这个改动不大但能让程序真正“输入任意给定 NFA”。5.5 现象状态转换图节点重叠、边穿过节点原因布局参数写死或未按状态数缩放解决圆周半径与节点尺寸随状态数动态计算图画出来能不能看取决于布局是否随输入自适应。节点半径固定、圆周半径固定状态一多就挤成一团。解决是把画布尺寸、圆周半径、节点直径都表示成状态数 n 的函数n 增大时同步放大边与节点之间留出边距。验收时拿 5 个状态和 12 个状态各画一次对比两次都不重叠才算通用。6. 验收与答辩怎么证明这套 ε-closure 实现是对的验收这套程序我一般不看代码写得多漂亮先看三组对照结果能不能对上。第一组用报告里的样例一状态集 X,1,2,3,4,5,6,Y字母表 a,b产生式包含多条 ε 弧跑完看所有状态子集的闭包是否覆盖完整、有没有漏掉经 ε 环可达的状态。第二组用样例二它带一个空状态子集的情况专门验证程序对空集的处理——空集的 ε-closure 按定义还是空集输出里应该能看到这一行不能崩也不能乱填。第三组自己构造一个含 ε 环的 NFA验证 5.2 的修复是否生效程序要能正常结束且闭包结果稳定。答辩时老师最爱问的两个问题提前准备好答案能省很多解释。一个是“为什么读 a 之后还要读空”回答要点是 ε-closure 的定义要求任意条 ε 弧读 a 到达的状态本身可能还有 ε 出边不读空就漏状态可以现场拿样例一里(5,a)→5再(5,ε)→1这条链举例。另一个是“你的子集构造怎么保证终止”回答要点是状态集有限子集总数上限是 2 的 n 次方每次只在新子集不在已有集合时才加入待处理队列集合不增就停配合 ε 环的已访问判断不会无限扩展。验收项检查方法合格标准文件读入保存读入后原样保存再读入两次解析结果一致全部子集闭包跑样例一、样例二每个子集都有对应闭包空集不崩单点查询任取一个子集查询与批量输出中同一子集结果相同ε 环鲁棒性自造含 ε 环 NFA正常结束闭包稳定状态转换图5 状态与 12 状态各画一次节点不重叠边不穿节点还有一个小技巧把“读空—读 a—读空”的组合函数单独拿出来做几个手工用例输入一个状态子集和一个字母纸上先算出期望结果再和程序输出比对。这比整程序跑一遍再猜哪里错要快得多。我当年做类似课设时就是整程序跑结果错了一个状态查了一下午后来才养成先测组合函数的习惯。从那以后我每次做子集构造相关的实现都强制先把moveThenClosure的手工用例跑通再往下写省下的时间远比写用例多。希望这套拆解能帮到你把这份课程设计报告稳稳交出去。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
数据库架构解析:从基础原理到高可用设计 1. 数据库架构基础认知数据库架构就像一座图书馆的管理系统。想象一下,当你走进图书馆查询某本书时,后台其实经历了一系列复杂的流程:前台接待员(连接层)接收你的请求,图书管理员(查询处理器&am… · 2026/11/8 5:30:13
基于HTML5与JavaScript的天气可视化项目开发指南 1. 项目概述最近完成了一个网页天气可视化项目,通过这个项目实现了在网页上动态展示天气数据的功能。这个项目结合了前端开发中的多项技术,包括HTML5、CSS3和JavaScript,以及第三方天气API的调用。作为一个实用的前端项目,它不仅能… · 2026/11/5 23:10:05
高校论文AI检测规避指南与工具实测 1. 项目背景与核心挑战2026届高校毕业生即将面临一项全新挑战:毕业论文AI生成内容比例需控制在20%以下。这项规定源于学术界对AI辅助写作工具泛滥的担忧,各大高校纷纷引入检测机制来维护学术诚信。作为经历过论文写作全流程的过来人,我实测了… · 2026/11/3 4:15:44
电工证 全国通用吗模拟考试题库 电工证全国通用吗?工地太忙根本没时间复习考试怎么破?值不值得考? 工地太忙根本没时间复习考试,很多电工朋友都面临这个问题,特别是像洛阳涧西区这样项目密集的区域,电工证成了刚需,但证书到底有没有全国通用?值不值得考?这事儿我太熟了,今天就给你… · 2026/11/8 5:29:29
电工作业培训档案官方回应:报名别被中介坑,这些细节要记牢 电工作业培训档案官方回应:报名别被中介坑,这些细节要记牢 不知道去哪报名怕被中介坑,这几乎是所有想考电工作业证的电工都遇到过的问题。最近,不少河南安阳的劳务班组负责人都在问:“电工作业培训档案怎么弄?”“官方回应有没有?”其实,… · 2026/11/8 5:29:29
电工证考要学什么 菜鸟也能考 在哪考全攻略 电工证考要学什么 菜鸟也能考 在哪考全攻略 你是不是也担心学历不高报不了电工证?别急,我之前就是个初中毕业的建筑工人,现在在濮阳干电工,每月拿8000多,靠的就是这张证。电工证考试其实门槛并不高,关键是你得知道 在哪考 ,还有… · 2026/11/8 5:29:29
井下哪里可以查电工证?2026河南最新政策下如何避免交了钱考不过 井下哪里可以查电工证?2026河南最新政策下如何避免交了钱考不过 怕考不过白交培训费?河南2026年特种作业电工证政策大变,很多人还没搞懂新规就报名了,结果钱花了,证没拿到,还耽误了工作机会。别急,今天我用济源市一位学员的真实案例,带你一步… · 2026/11/8 5:29:29
考电工证没用怎么考 电工证考了没用?郑州报考避坑指南全攻略 怕考不过白交培训费?这年头,考个电工证还没用,听起来像是个大坑。尤其是郑州这边,特种作业证报考门槛高、费用贵,还不一定能一次性通过,让人头疼。如果你正打算考电工证,或者正在犹豫要不要考,这篇【郑州报考… · 2026/11/8 5:28:29
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/8 0:00:20
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/8 0:00:20
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/8 0:00:20
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/8 0:00:20
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/8 0:00:20
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/8 0:00:20
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 11:25:08
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 12:02:18
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/8 1:18:25