ARTICLE · 1128622
实战|用 AI 写 CAD 插件:文字搜索统计(附源码 + 提示词)
点击蓝字,关注我们这是《零基础 CAD 插件从 0 到 1》第 17 篇
小伙伴想让我做一个文字统计工具
确实有时候想统计点东西用cad的命令确实有点麻烦
比如:想数一数图上有多少个“门”、多少个“窗”,或者统计一下材料表里各种规格出现了多少次。手动找?眼睛看花不说,还容易漏。用 CAD 自带的查找?只能一个一个找,没法批量统计,更没法导出。
更烦的是,有些文字在块里面,有些是属性文字,还有些大小写不统一、前后带空格,统计起来简直要命。
今天咱们用 AI 写一个文字统计小助手,从根上解决“数文字”的麻烦:框选区域 → 自动统计 → 列表显示 → 支持搜索、复制、导出 CSV。走哪带哪,一键搞定
先看效果:打开窗口框选直接搜索

点击蓝字,关注我们这是《零基础 CAD 插件从 0 到 1》第 17 篇
小伙伴想让我做一个文字统计工具
确实有时候想统计点东西用cad的命令确实有点麻烦
比如:想数一数图上有多少个“门”、多少个“窗”,或者统计一下材料表里各种规格出现了多少次。手动找?眼睛看花不说,还容易漏。用 CAD 自带的查找?只能一个一个找,没法批量统计,更没法导出。
更烦的是,有些文字在块里面,有些是属性文字,还有些大小写不统一、前后带空格,统计起来简直要命。
今天咱们用 AI 写一个文字统计小助手,从根上解决“数文字”的麻烦:框选区域 → 自动统计 → 列表显示 → 支持搜索、复制、导出 CSV。走哪带哪,一键搞定
先看效果:打开窗口框选直接搜索

GIF1(打开窗口):输入 STEXT → 弹出文字统计窗口 → 上方是框选和选项,中间是结果表格,底部是复制导出按钮,整体清爽,不抢 CAD 焦点。

GIF2(框选统计):点“框选区域” → 窗口自动隐藏 → 在图纸上框选 → 窗口重新出现,列表里已经按数量从多到少排好了。

GIF3(搜索过滤):在搜索框输入关键词 → 列表实时过滤,支持“包含匹配”和“全词匹配”。
这个插件解决了什么问题?
针对文字统计的五大痛点,做了五个核心优化:
一键框选统计
不用一个一个选,框选区域后自动提取所有文字,包括普通文字、多行文字、块里的属性文字,甚至嵌套块里的文字也能挖出来。忽略大小写和空格
勾选“忽略大小写”,Door和door算一种;勾选“忽略首尾空格”,门和门算一种。统计更准确。结果自动排序
按出现次数从多到少排列,一眼就能看出哪种文字最多。搜索过滤
结果多了不好找?搜索框输入关键词,支持“包含匹配”和“全词匹配”,瞬间筛选。复制和导出
一键复制到剪贴板,直接粘贴到 Excel;或者导出 CSV 文件,方便存档和汇报。不抢焦点
窗口打开后不抢 CAD 焦点,鼠标直接移到图纸上就能框选。框选时窗口自动隐藏,完成后自动显示,流程顺畅。
交互设计:从框选到数据导出

输入 STEXT 回车,弹出文字统计窗口。窗口清爽,不抢 CAD 焦点,鼠标可以直接移到图纸上操作。
点“框选区域”,窗口会自动隐藏,让你在图纸上框选。框选完成后,窗口重新出现,结果已经按数量从多到少排好,列在中间的表格里。表格有两列:文字内容、数量。
如果结果太多不好找,上面搜索框输入关键词,列表实时过滤。默认是“包含匹配”,勾上“全词匹配”就只显示完全一样的文字。搜索框旁边还会显示当前筛出来的项数和合计数量,比如“共 12 项,合计 48”。
觉得统计没问题了,底下按钮一点:复制结果,直接粘贴到 Excel;或者导出 CSV,带 BOM,Excel 打开不乱码。想重新框选,点“重新框选”就行,窗口不用关。
整个窗口从上到下就是:标题栏(能拖动)、框选和选项按钮、搜索栏、结果表格、底部操作按钮、状态提示。没有多余的东西,用起来顺手。
核心干货:给 AI 的精准提示词
还是那句话:用 AI 写插件写出来的功能不对,本质是需求没说细。
下面是实测多轮、输出稳定能用的提示词模板:
角色设定你是资深 CAD 插件开发工程师,用 C# 和 WPF 做 AutoCAD 插件。 功能需求开发一个「文字统计」插件,命令名 STEXT。 核心目标解决“图纸文字统计麻烦”的问题。用户框选一个区域,自动统计区域内所有文字的出现次数,支持忽略大小写、忽略首尾空格,结果可以搜索、复制、导出。 界面WPF 无边框圆角窗口,毛玻璃卡片风格:
功能要求窗口行为
文字统计
搜索过滤
复制和导出
环境.NET Framework 4.8,用 AcMgd、AcDbMgd、AcCoreMgd 三个引用。 输出要求完整可编译的代码,分几个文件,关键逻辑加中文注释,说明怎么编译、怎么在 CAD 里加载。 |
写提示词的核心原则
先定身份先让 AI 进入专业 CAD 开发的角色,避免用错 API、写出行外代码。
再划边界明确命令名、CAD 版本、运行环境,从根源减少兼容问题和报错。
讲清规则怎么保存、怎么注入、怎么设为当前,每一步规则都说死,不给 AI 自由发挥的空间。
固定格式要完整代码、要注释、要部署说明,都明确提出来,输出直接能用。
照着这个结构写,AI 输出代码的可用率至少提升 80%。
核心源码分享
下面是核心实现代码,基于 C# + CAD .NET API 编写
using System;using System.Collections.Generic;using System.Linq;using System.Windows.Controls;using Autodesk.AutoCAD.ApplicationServices;using Autodesk.AutoCAD.DatabaseServices;using Autodesk.AutoCAD.EditorInput;namespace SheetCount{///<summary>/// 文字统计核心///</summary>public static class TextCounter{///<summary>/// 框选,然后统计区域内所有文字///</summary>publicstatic List<CountRow> Run(Document doc, bool ignoreCase, bool trim){// 1. 让用户框选var pso = new PromptSelectionOptions();pso.MessageForAdding = "\n请框选要统计的区域: ";var psr = doc.Editor.GetSelection(pso);if (psr.Status != PromptStatus.OK) return null;ObjectId[] ids = psr.Value.GetObjectIds();if (ids.Length == 0) return new List<CountRow>();// 2. 统计var counter = new Dictionary<string, int>(StringComparer.Ordinal);var displayName = new Dictionary<string, string>(StringComparer.Ordinal);using (doc.LockDocument())using (var tr = doc.Database.TransactionManager.StartTransaction()){foreach (ObjectId id in ids){var ent = tr.GetObject(id, OpenMode.ForRead) as Entity;if (ent == null) continue;// 直接实体ExtractFromEntity(ent, tr, counter, displayName, ignoreCase, trim);// 块参照 → 递归取块内文字var br = ent as BlockReference;if (br != null){ExtractFromBlockRef(br, tr, counter, displayName,ignoreCase, trim, new HashSet<ObjectId>());}}tr.Commit();}// 3. 转成列表并按数量降序var result = new List<CountRow>();foreach (var kv in counter){result.Add(new CountRow{Text = displayName[kv.Key],Count = kv.Value});}return result.OrderByDescending(r => r.Count).ThenBy(r => r.Text).ToList();}// =====================================================// 从一个实体里提取文字// =====================================================privatestaticvoidExtractFromEntity(Entity ent,Transaction tr,Dictionary<string, int> counter,Dictionary<string, string> displayName,bool ignoreCase,bool trim){string content = null;var dbText = ent as DBText;if (dbText != null){content = dbText.TextString;}else{var mText = ent as MText;if (mText != null){content = mText.Contents;// 去掉多行文字的格式代码content = mText.Text;}else{var attr = ent as AttributeReference;if (attr != null){content = attr.TextString;}}}if (string.IsNullOrEmpty(content)) return;AddToCounter(content, counter, displayName, ignoreCase, trim);}// =====================================================// 递归统计块参照里的文字// =====================================================privatestaticvoidExtractFromBlockRef(BlockReference br,Transaction tr,Dictionary<string, int> counter,Dictionary<string, string> displayName,bool ignoreCase,bool trim,HashSet<ObjectId> visited){// 防止循环嵌套的块if (br.BlockTableRecord == ObjectId.Null) return;if (visited.Contains(br.BlockTableRecord)) return;visited.Add(br.BlockTableRecord);// 块属性foreach (ObjectId attId in br.AttributeCollection){var att = tr.GetObject(attId, OpenMode.ForRead) as AttributeReference;if (att == null) continue;if (string.IsNullOrEmpty(att.TextString)) continue;AddToCounter(att.TextString, counter, displayName, ignoreCase, trim);}// 块定义内部的实体var btr = tr.GetObject(br.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;if (btr == null) return;foreach (ObjectId eid in btr){var inner = tr.GetObject(eid, OpenMode.ForRead) as Entity;if (inner == null) continue;ExtractFromEntity(inner, tr, counter, displayName, ignoreCase, trim);// 嵌套块var innerBr = inner as BlockReference;if (innerBr != null){ExtractFromBlockRef(innerBr, tr, counter, displayName,ignoreCase, trim, visited);}}}// =====================================================// 把一条文字加进统计表// =====================================================privatestaticvoidAddToCounter(string content,Dictionary<string, int> counter,Dictionary<string, string> displayName,bool ignoreCase,bool trim){string display = content;if (trim) display = display.Trim();if (string.IsNullOrEmpty(display)) return;string key = ignoreCase ? display.ToUpperInvariant() : display;int c;if (counter.TryGetValue(key, out c)){counter[key] = c + 1;}else{counter[key] = 1;displayName[key] = display;}}}}
用 AI 开发插件的完整流程
需求拆解
把「文字统计」拆成五个模块:窗口框架 → 框选获取文字 → 统计计数 → 列表显示与搜索 → 复制导出。逐个让 AI 实现。
分步验证
先做“能框选并读出文字”,再做“能统计并排序”,最后做“搜索、复制、导出”。每一步跑通再往下,出问题好定位。
实测优化
拿不同 CAD 版本测试:2021、2024 都有细微差异。踩的坑包括:
块内文字提取不全,后来加了递归遍历块定义;
忽略大小写时,显示的文字还是原始大小写,但统计键统一转大写;
框选时窗口隐藏后,CAD 没有及时获得焦点,加了延时和激活;
导出 CSV 时没加 BOM,Excel 打开中文乱码。
细节调整
窗口大小、按钮颜色、默认勾选状态、列表行高,都可以根据自己的操作习惯改。
成品领取 & 下期预告
成品插件直接领
不想自己编译、调代码的朋友,关注公众号 「下班让AI教我做插件」,后台回复 「文字统计」,直接领取编译好的 DLL 插件文件,NETLOAD 加载或者是使用我写的dll插件加载工具箱。 完整工程源码拿到手就能二次修改。
下期预告
下一篇咱们继续图纸提效工具,如果有想要的插件可以在评论区留言,我看看哪个留言最多就做哪个。
我是做插件的设计师,专注用 AI 提高 CAD 设计效率。关注我,下班一起做插件,把重复工作交给程序。
声明
本插件完全免费分享,仅供交流学习使用。严禁任何人将其用于商业倒卖或牟利。如需转载,请注明出处。请大家尊重作者的劳动成果,共同维护良好的交流环境。

E
N
D