CAD多文件文本批量替换:跨图纸改代号的脚本实现与避坑指南
简介这份资源面向需要处理大量CAD图纸的工程师与设计人员解决多文件间相同文本批量替换的痛点——并非单文件内多处替换而是跨多个独立CAD文件同步更新关键文本避免逐一手动查找修改。压缩包共6个文件约1.88MB包含exe可执行程序、ocx控件、chm帮助文档、htm说明页及avi视频教程覆盖从运行环境到操作演示的完整链路。目前已有2294人学习下载说明该工具在CAD批量处理场景中具备一定实用价值。读者可获得一套可直接运行的批量文本替换工具配合说明文档与视频教程快速上手理解文件列表准备、替换规则设定、脚本或工具执行及结果校验的完整流程从而在大型工程图纸或设计项目中高效保证文本一致性显著减少重复劳动。1. 图纸改一个字为什么要动几十个文件上周帮一个做机械设计的朋友处理一批图纸他接了个改版项目甲方要求把整套图纸里的某个设备代号从旧编号换成新编号。听起来就是「查找替换」四个字的事但他手里是 60 多张 DWG 图纸每张图里这个代号出现在标题栏、明细表、技术要求说明、图层名甚至块属性里。他一开始打算一张张打开手动改改到第 8 张就崩溃了——因为漏改了一处打印出来的图纸和电子版对不上被审图的打回来重做。这就是 cad 文本批量替换多文件相同文本要解决的问题不是单张图纸里替换一个词而是跨多个文件、把同一段文本在所有可能出现的位置一次性换掉还要保证替换后图纸能正常打开、文字样式不乱、块属性不丢。它适合两类人一类是经常做改版、换图号、换设备编号的设计和绘图岗另一类是要处理历史图纸归档、把旧标准文本统一成新标准的资料管理岗。核心难点从来不是「替换」这个动作而是「多文件」和「相同文本」这两个限定词带来的批量一致性问题。2. 先搞清楚文本藏在哪CAD 里文本的五种载体动手写脚本之前必须先把「文本」这个概念拆开。很多人翻车就翻在以为 CAD 里的文字只有一种结果替换完发现标题栏变了、明细表没变或者反过来。CAD 图纸里的文本至少分布在五个地方替换策略完全不同。2.1 单行文字、多行文字与属性块的区别单行文字TEXT/DTEXT和多行文字MTEXT是最直观的用常规的查找替换就能命中。但属性块ATTRIB里的文字是挂在块参照上的它不在模型空间的文字实体列表里而是作为块的属性存在。如果你只用处理 TEXT 和 MTEXT 的逻辑去遍历属性块会被整个跳过。这是第一个大坑。还有两个容易被忽略的标注文字DIMENSION 的测量值和替代文字和表格文字TABLE 单元格。标注文字如果用的是测量值自动生成你替换文本是没用的得改标注样式或者改替代文字表格文字在底层可能是 MTEXT也可能是表格对象自己的单元格数据取决于 CAD 版本和创建方式。文本载体实体类型是否在常规文字遍历中替换注意点单行文字TEXT是直接改 TextString多行文字MTEXT是注意格式代码别破坏控制符属性块ATTRIB否需遍历块参照的 Attribute 集合标注文字DIMENSION否区分测量值与替代文字表格文字TABLE部分单元格数据需单独处理2.2 用脚本枚举一张图纸里所有文本实体在批量替换之前我一般先写一个「侦察脚本」把一张图纸里所有文本实体和它们的类型、内容、所在图层打印出来。这样你能确认目标文本到底藏在哪种载体里避免盲目替换。下面用 Python 配合常见的 CAD 二次开发库来演示思路不同库 API 名称有差异重点是遍历逻辑。# 侦察脚本枚举当前图纸中所有文本类实体 # 假设使用某 CAD Python 接口doc 为当前文档对象 def scan_all_text(doc): results [] # 1. 遍历模型空间所有实体 for entity in doc.model_space: etype entity.type_name # 实体类型名 if etype in (TEXT, MTEXT): results.append((etype, entity.layer, entity.text_string)) elif etype INSERT: # 2. 块参照遍历其属性 for att in entity.attributes: results.append((ATTRIB, att.layer, att.text_string)) elif etype DIMENSION: # 3. 标注只取替代文字测量值不在这里 if entity.text_override: results.append((DIM_OVERRIDE, entity.layer, entity.text_override)) # 4. 表格单独处理 for table in doc.tables: for row in table.rows: for cell in row.cells: if cell.text: results.append((TABLE_CELL, table.layer, cell.text)) return results # 打印结果人工确认目标文本的载体类型 for item in scan_all_text(doc): print(item)这段代码的逻辑是分层遍历先扫模型空间的普通实体遇到块参照就下钻到属性遇到标注就只取替代文字最后单独扫表格。参数上要注意text_override这个属性只有标注被手动改过文字才有值自动测量值是空的。跑完这个脚本你会得到一张清单明确知道「要替换的那个代号」出现在哪些载体里。如果它只出现在 TEXT 和 MTEXT 里后面的替换逻辑可以简化如果出现在 ATTRIB 里就必须加上块属性的处理分支。提示侦察脚本一定要在副本上跑不要直接对原始图纸操作。批量处理的第一原则是永远保留一份未改动的原始文件。3. 批量替换的三种落地路径与选型搞清楚文本载体之后接下来是选工具。批量替换 CAD 文本有三条主流路径CAD 自带命令、脚本批处理、第三方工具。三条路各有适用场景选错了要么效率低要么改坏图纸。3.1 CAD 自带查找替换能不能跨文件CAD 自带的 FIND 命令可以在单张图纸内查找替换部分版本支持在当前打开的多张图纸间切换但它本质上还是「打开一张、替换一张」没法对一批未打开的文件做批处理。而且 FIND 对属性块和表格的支持取决于版本有的版本能命中属性有的不能。所以自带命令适合「文件数量少、文本载体简单」的场景比如就改三五张图里的普通文字。一旦文件上到几十张或者目标文本藏在属性块里自带命令就不够用了必须上脚本。3.2 用脚本做跨文件替换的完整流程脚本批处理是处理多文件相同文本最可靠的方式。核心流程分四步遍历目录收集文件、逐个打开、执行替换、保存关闭。下面是一个完整的批处理框架。import os # 配置区替换规则和文件范围 TARGET_DIR rD:\drawings\batch_01 # 图纸所在目录 OLD_TEXT EQ-2021-A # 被替换的旧文本 NEW_TEXT EQ-2024-B # 替换后的新文本 FILE_EXT .dwg # 文件扩展名 def replace_in_entity(entity, old, new): 对单个实体执行替换返回是否发生替换 changed False etype entity.type_name if etype in (TEXT, MTEXT): if old in entity.text_string: entity.text_string entity.text_string.replace(old, new) changed True elif etype INSERT: for att in entity.attributes: if old in att.text_string: att.text_string att.text_string.replace(old, new) changed True return changed def process_file(filepath, old, new): 处理单个图纸文件 doc open_document(filepath) # 打开图纸 count 0 for entity in doc.model_space: if replace_in_entity(entity, old, new): count 1 # 表格单独处理 for table in doc.tables: for row in table.rows: for cell in row.cells: if cell.text and old in cell.text: cell.text cell.text.replace(old, new) count 1 doc.save() # 保存 doc.close() # 关闭 return count def batch_process(target_dir, old, new, ext): 批量遍历目录 total_files 0 total_changes 0 for root, dirs, files in os.walk(target_dir): for fname in files: if fname.lower().endswith(ext): fpath os.path.join(root, fname) n process_file(fpath, old, new) total_files 1 total_changes n print(f{fname}: 替换 {n} 处) print(f共处理 {total_files} 个文件替换 {total_changes} 处) batch_process(TARGET_DIR, OLD_TEXT, NEW_TEXT, FILE_EXT)这段代码的关键设计点有三个。第一replace_in_entity把替换逻辑按实体类型分开TEXT/MTEXT 走一条路INSERT 的属性走另一条路这样不会漏掉属性块。第二process_file里对表格做了单独遍历因为表格单元格不在模型空间的普通实体列表里。第三batch_process用os.walk递归遍历目录能处理子文件夹里的图纸。参数上要特别注意OLD_TEXT和NEW_TEXT的匹配方式。上面用的是简单子串替换如果旧文本是另一个词的一部分会误伤。比如旧代号是A-01而图里有个XA-012简单替换会把XA-012变成XEQ-2024-B2。解决办法是用正则加词边界或者替换前先确认旧文本不会作为其他文本的子串出现。3.3 第三方批量工具适合什么场景市面上有一些专门的 CAD 批量处理工具支持跨文件查找替换界面化操作不用写代码。它们适合不熟悉脚本、文件量中等、替换规则简单的场景。但第三方工具的局限在于对属性块和表格的支持参差不齐有的工具只处理普通文字替换规则不够灵活没法做正则和条件判断遇到加密或特殊格式的图纸可能直接失败。我的经验是如果替换规则固定、文件量大、要求可重复执行脚本更可控如果只是偶尔处理一批、不想折腾环境第三方工具能省事。4. 避坑指南批量替换最容易翻车的五个地方批量替换这件事写脚本只占三成时间剩下七成都在处理各种意外。下面五条是我踩过的坑每条都按「现象 → 原因 → 解决」说清楚。4.1 替换后图纸打不开或提示文件损坏现象批处理跑完部分图纸打开时报错或者直接卡死。原因通常是保存时文件被占用或者脚本在文档还没完全加载时就执行了替换导致写入不完整。解决在open_document之后加一个就绪检查确认文档完全加载再操作保存前先另存为新文件不要覆盖原文件处理完一个文件后确保close真正释放了句柄再处理下一个。4.2 属性块里的文字没被替换现象普通文字都改了标题栏里的属性文字纹丝不动。原因就是前面说的属性块文字不在模型空间的文字实体列表里只遍历 TEXT/MTEXT 会整个跳过。解决在遍历时判断实体类型为 INSERT然后下钻到它的 attributes 集合逐个替换。如果块是动态块还要注意可见性状态下的属性可能不同。4.3 多行文字的格式代码被破坏现象替换后多行文字显示异常比如颜色变了、换行没了、堆叠分数散了。原因是 MTEXT 的内容里含有格式控制代码比如\P表示换行、\f表示字体、\H表示字高。如果你的替换逻辑对整段字符串做操作可能把控制符也改掉。解决替换时只针对纯文本部分或者用库提供的文本设置接口而不是直接改原始字符串。更稳妥的做法是替换前先备份原始内容替换后对比格式代码是否完整。4.4 大小写和全半角导致漏替换现象明明图里有那个文本脚本报告替换 0 处。原因是 CAD 里的文本可能大小写不一致或者中英文标点、全半角混用。比如旧文本是EQ-2021-A图里写的是eq-2021-a或者用了全角连字符。解决替换前统一做大小写归一化或者用不区分大小写的匹配对全半角问题先做字符规范化再匹配。这一步建议在侦察阶段就确认清楚目标文本的实际写法。4.5 批量处理中途失败没有回滚现象处理到第 30 个文件时报错中断前 29 个已经改了后 30 个没动状态不一致。原因是脚本没有异常处理和进度记录。解决每个文件处理前先记录日志处理成功和失败都写清楚出错时不要直接退出捕获异常后跳过当前文件继续处理最后汇总失败列表重要项目先在全量副本上跑确认无误再对正式文件操作。注意批量替换前一定要做全量备份并且备份要和原文件在不同目录。我见过有人备份到同一个目录结果脚本遍历时把备份也改了。5. 让替换更稳的几个进阶技巧前面讲的流程能覆盖大部分场景但实际项目里总有些边界情况需要额外处理。这一章说几个让批量替换更稳的技巧都是我在反复翻车后固化下来的习惯。5.1 用替换清单文件驱动而不是硬编码当替换规则不止一条时把规则写死在脚本里很危险改一次就要动代码。更好的做法是维护一个替换清单文件比如 CSV 或 JSON脚本读取清单逐条执行。这样非开发人员也能维护规则而且清单本身就是操作记录。import csv def load_rules(rule_file): 从 CSV 加载替换规则格式旧文本,新文本 rules [] with open(rule_file, r, encodingutf-8) as f: reader csv.reader(f) for row in reader: if len(row) 2: rules.append((row[0], row[1])) return rules # 使用rules load_rules(replace_rules.csv) # 对每个实体依次应用所有规则 def apply_rules(text, rules): for old, new in rules: if old in text: text text.replace(old, new) return text清单驱动的好处是可追溯这次改了什么、改了哪些词清单文件一目了然。参数上注意 CSV 的编码要用 UTF-8否则中文文本会乱码。规则顺序也有讲究如果两条规则存在包含关系比如先替换A-01再替换A-01-B顺序错了会误伤一般把长的规则排在前面。5.2 替换前后的校验数量对账与抽样检查批量替换最怕的是「以为改完了其实漏了」或者「改多了」。我的习惯是替换前后各做一次统计替换前统计目标文本在所有文件里出现的总次数替换后统计新文本出现的次数两者应该一致。如果替换后旧文本还有残留说明有载体没覆盖到如果新文本数量对不上说明有误替换。def count_text_occurrences(target_dir, keyword, ext): 统计关键词在所有图纸中出现的总次数 total 0 for root, dirs, files in os.walk(target_dir): for fname in files: if fname.lower().endswith(ext): doc open_document(os.path.join(root, fname)) for entity in doc.model_space: if entity.type_name in (TEXT, MTEXT): total entity.text_string.count(keyword) elif entity.type_name INSERT: for att in entity.attributes: total att.text_string.count(keyword) doc.close() return total # 替换前 before count_text_occurrences(TARGET_DIR, OLD_TEXT, FILE_EXT) # 执行替换... # 替换后 after_old count_text_occurrences(TARGET_DIR, OLD_TEXT, FILE_EXT) after_new count_text_occurrences(TARGET_DIR, NEW_TEXT, FILE_EXT) print(f替换前旧文本 {before} 处替换后旧文本残留 {after_old} 处新文本 {after_new} 处)这段对账逻辑跑完如果after_old是 0 且after_new等于before基本可以确认替换完整且没有误伤。如果after_old不为 0就要回到侦察脚本看是哪种载体漏了。抽样检查则是随机打开几张图纸肉眼确认标题栏、明细表、技术要求这些关键位置的文字是否正确。5.3 处理只读文件和被占用文件的策略批量处理时经常遇到文件是只读的或者被其他程序占用。脚本直接打开会失败。我的处理策略是先检查文件属性如果是只读就先去掉只读属性处理完再恢复如果文件被占用记录到失败列表等所有文件处理完后再单独处理这批。不要因为一个文件失败就中断整个批次那样前面的工作白做后面的也没动。import stat def ensure_writable(filepath): 确保文件可写返回原始权限以便恢复 original os.stat(filepath).st_mode os.chmod(filepath, original | stat.S_IWRITE) return original def restore_permission(filepath, original_mode): 恢复原始权限 os.chmod(filepath, original_mode)这套权限处理看起来琐碎但在处理归档图纸时特别有用很多历史文件默认是只读的。恢复权限这一步别省否则改完之后文件属性变了可能影响后续的归档流程。5.4 一个我坚持了多年的操作习惯最后说个习惯层面的东西。每次做批量替换我都会先拿 3 到 5 张有代表性的图纸做小批量试跑确认替换结果正确、图纸能正常打开、关键位置文字无误之后再对全量文件执行。这个试跑成本很低但能挡住绝大多数低级错误。另外替换脚本和替换清单我会和图纸放在一起归档下次再有类似需求直接改清单就能复用不用重新写逻辑。批量替换这件事稳比快重要一次改错几十张图纸返工的时间远超多花的那点验证时间。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

用MATLAB从零搭建OFDM系统:原理、仿真与踩坑指南

用MATLAB从零搭建OFDM系统:原理、仿真与踩坑指南

1. OFDM到底在干什么:一个直觉式入门很多朋友第一次接触OFDM(正交频分复用,Orthogonal Frequency Division Multiplexing)是在4G、5G或者Wi-Fi 6的教材里,感觉这东西离自己很远。其实OFDM已经是你手机里每天都在跑的底…

2026/10/11 13:46:08 阅读更多 →
基于mediasoup的SFU多人语音房:优化、监控与断线排障

基于mediasoup的SFU多人语音房:优化、监控与断线排障

我们团队最近在一款社交产品的多人语音房场景里,基于mediasoup把原本单路转发的架构升级成了SFU模式,断断续续调了小两个月。这中间踩了无数坑,也沉淀了一套从实现、监控到排障的完整思路。这篇文章就是把这段实践梳理一遍,重点放…

2026/10/11 13:46:08 阅读更多 →
图书销售管理系统数据库设计:建表、外键、事务与避坑指南

图书销售管理系统数据库设计:建表、外键、事务与避坑指南

简介:这是一份面向数据库课程设计或初学者的图书销售管理系统数据库设计文档,配套SQL Server实现,完整覆盖从项目背景、需求分析、概念模型设计到逻辑模型设计、建库录入、数据库操作及问题解决的全流程。资源以docx格式提供,共1个…

2026/10/11 13:45:08 阅读更多 →

最新新闻

SSM+Vue红色旅游网站毕业设计全流程实战指南

SSM+Vue红色旅游网站毕业设计全流程实战指南

每年一到毕设季,“年份技术栈地名主题网站”这个格式的题目就会扎堆出现。最近被问得特别多的是这个方向:2026届毕业设计,SSMVue做一个某中部城市的红色旅游网站,还要配套论文和可运行程序。这类题目乍一看确实老套,城…

2026/10/11 14:40:40 阅读更多 →
基于SpringBoot的校园失物招领系统:从零复现与论文配套的毕设全流程

基于SpringBoot的校园失物招领系统:从零复现与论文配套的毕设全流程

简介:在B/S架构与MVC分层思想下,SpringBoot通过自动配置大幅降低了Web项目的搭建成本,MyBatis则以灵活的SQL映射支撑多表联查与条件筛选。这套技术组合在高校毕设中尤为常见,尤其适合实现校园失物招领这类业务边界清晰、状态流转严…

2026/10/11 14:40:40 阅读更多 →
SpringBoot+Vue+MyBatis+MySQL网购管理系统:架构拆解与部署实战

SpringBoot+Vue+MyBatis+MySQL网购管理系统:架构拆解与部署实战

从 2025 年初开始,后台几乎每天都能收到类似的私信:"有没有现成的网购平台管理系统源码?"、"SpringBoot 和 Vue 怎么拼起来才算规范?"、"前后端分离的项目到底怎么部署?"。问的人多了&a…

2026/10/11 14:40:40 阅读更多 →
Oracle 19c SQL函数权威指南:从TO_DATE报错到JSON_TABLE实战

Oracle 19c SQL函数权威指南:从TO_DATE报错到JSON_TABLE实战

简介:本资源是Oracle数据库19c官方SQL语言参考手册的中文整理版,面向数据库开发工程师、DBA及SQL进阶学习者,系统解决Oracle特有函数查用难、分类杂、新特性不熟悉等实际问题。手册覆盖数学、字符串、日期时间、类型转换、加密、集合等六大类…

2026/10/11 14:40:40 阅读更多 →
Eclipse Theia 进程管理扩展深入解析:`@theia/process` 的架构、生命周期与实战指南

Eclipse Theia 进程管理扩展深入解析:`@theia/process` 的架构、生命周期与实战指南

IDE代码编辑器开发工具前端桌面应用插件系统后端AI 应用 【免费下载链接】theia Eclipse Theia is a cloud & desktop IDE framework implemented in TypeScript. 项目地址: https://gitcode.com/gh_mirrors/th/theia 点击查看 免费下载 theia/process 是 Ecli…

2026/10/11 14:40:40 阅读更多 →
图书销售管理系统数据库设计:从ER图到第三范式全流程实战

图书销售管理系统数据库设计:从ER图到第三范式全流程实战

简介:面向数据库课程大作业的图书销售管理系统数据库设计文档,完整覆盖从需求分析到实现操作的全流程。文档以SQL Server为平台,围绕图书信息、库存、销售记录、客户关系等核心模块展开,包含全局与局部ER图、逻辑表结构&#xff0…

2026/10/11 14:39:40 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →