能,scalpel通过模式匹配提取todo和自定义注解,不依赖ast解析而基于文本扫描,支持上下文捕获、语言感知过滤字符串字面量、csv/json导出及多语言项目分步处理。

scalpel 能直接提取 TODO 和自定义注解吗?
能,但不是靠“语义理解”,而是靠模式匹配。scalpel 不解析 AST,它把源码当文本扫,所以 TODO、@Deprecated、@ApiVersion("v2") 这类字符串只要写在代码里(哪怕在字符串字面量或注释中),默认就会被匹配到——这既是优势,也是坑。
实操建议:
- 用
--pattern指定正则,比如scalpel --pattern "TODO|FIXME" *.java,注意引号防止 shell 展开 - 加
--context-lines 2输出前后两行,避免只看到孤立的// TODO而不知道上下文是哪个函数 - 若只想匹配注解(如
@Loggable),用--pattern "@[A-Za-z0-9_]+(?:\([^)]*\))?",但需确认目标语言是否用括号传参(Java 是,Python decorator 可能不带) - 慎用
--ignore-comments:它会跳过所有注释块,但很多TODO就写在//或/* */里,关了反而漏掉
为什么 grep 不能替代 scalpel 提取注解?
grep 确实能搜 TODO,但它无法区分“代码里的 TODO 字符串”和“注释里的 TODO”。scalpel 的关键价值在于结构感知:它知道哪段是注释、哪段是字符串、哪段是真实代码块,能按语法边界截取完整上下文。
常见错误现象:
- 用
grep -r "TODO" .扫出几百条结果,其中一半是测试用例里故意写的"TODO: fix this"字符串,纯噪音 - 想提取所有
@RestController类,但grep "@RestController" *.java会把class MyController {这一行单独输出,没包含类体 - scalpel 则可通过
--block-type class+--pattern "@RestController",自动捕获整个类定义块
如何避免误匹配字符串字面量中的 TODO?
这是最常踩的坑。scalpel 默认不跳过字符串,所以 logger.info("User login failed: TODO handle retry"); 也会被命中。解决方法不是禁用字符串扫描,而是利用其上下文标记能力。
实操建议:
- 加
--exclude-pattern '"[^"]*TODO[^"]*"' --exclude-pattern "'[^']*TODO[^']*'"排除双/单引号包裹的 TODO(注意转义) - 更稳妥的做法是启用语言感知:scalpel 对 Java/Python 等支持基础词法识别,运行时加
--lang java,它会自动忽略字符串和注释内的匹配——前提是你的文件后缀正确(.java),否则 fallback 到纯文本模式 - 验证是否生效:对一个含
"TODO"字符串的文件跑scalpel --lang java --pattern TODO test.java | wc -l,结果应为 0;去掉--lang java后应大于 0
提取结果怎么导出成可审计的清单?
scalpel 默认输出到终端,但审计需要结构化数据。它支持 --output-format json 和 --output-file report.json,但 JSON 字段较原始,真正有用的是 --output-format csv。
关键参数组合:
-
--output-format csv --output-file todos.csv --fields file,line,content,context:生成含文件路径、行号、匹配内容、上下文的 CSV,Excel 直接打开可排序筛选 - 加
--sort-by line让结果按行号升序,方便定位 - 若要合并多个项目的结果,别用
>>追加 CSV——表头会重复。改用scalpel ... --output-format csv --output-file part1.csv,再用 Python 或 awk 去重表头 - 注意:CSV 中的
content字段可能含换行符,scalpel 会自动用双引号包裹,Excel 能正确解析,但 Vim 查看需设:set fileformat=unix
复杂点在于混合语言项目:同一个 repo 里有 Java、JS、Python 文件,--lang 只能指定一种。此时要么分三次扫描,要么接受部分误匹配——没有银弹,得根据审计优先级权衡。











