Cursor2.0与Trae2.10评测:8款大模型注释能力横评,谁才是代码好帮手?
本文对Cursor2.0和Trae2.1平台下的六个大语言模型在代码中文注释生成能力进行了系统评测。评测采用统一的Java代码文件和提示词条件,重点比较了Sonet4.5、Composer、Deepseek 3.1 Terminus等主流模型表现。结果显示各模型在注释风格和细节处理上存在显著差异:Sonet4.5提供结构化的类级和方法级注释,包含详细功能说明和应用场景;Deepseek 3.1 T
引言
评测背景与目的
在软件开发中,清晰的代码注释是提升可读性和团队协作效率的关键,尤其是中文注释能帮助开发者快速理解逻辑、减少沟通成本。随着人工智能技术的进步,大语言模型在辅助编程注释方面应用日益广泛,自动化生成注释成为提升开发效率的新趋势。为此,本次评测聚焦于比较Cursor2.0和Trae2.1工具下的六款大模型(Sonet4.5、Composer、Deepseek 3.1 Terminus、Qwen3-coder、GLM-4.6、Kimi-K2),针对MarkdownSplitter.java代码,使用统一提示词“@选中代码文件,请给代码补充中文注释”进行测试。评测旨在评估各模型生成中文注释的能力,探讨哪个模型更能胜任“好同事”角色,为开发者提供实用参考。
评测方法
评测设置概述
本次评测采用统一的测试环境,以确保结果的公平性和可比性。我们使用固定的Java代码文件MarkdownSplitter.java作为测试对象,并应用相同的提示词“@选中代码文件,请给代码补充中文注释”来评估各模型的注释生成能力。评测工具包括Cursor 2.0和Trae 2.1:Cursor 2.0是一款AI驱动的代码编辑器,支持智能代码补全和注释生成;Trae 2.1则是一个多模型集成平台,专注于代码优化和文档辅助。在Cursor 2.0中,我们分别测试了Sonet 4.5和Composer模型,用户可通过工具界面直接选择模型并执行注释任务;在Trae 2.1中,则评测了Deepseek 3.1 Terminus、Qwen3-coder、GLM-4.6和Kimi-K2模型,通过平台配置模型参数并运行相同提示词。所有模型均在相同代码文件和提示词条件下测试,确保环境一致,避免外部变量干扰。测试流程包括加载代码文件、应用提示词、生成注释并记录输出,从而系统性地比较各模型的表现。
评测工具与模型列表
| 工具名称 | 模型名称 | 模型简要描述 |
|---|---|---|
| Cursor2.0 | Sonet4.5 | 强大的通用模型,提供详细的代码注释和示例 |
| Cursor2.0 | Composer | 代码生成与优化模型,擅长结构化代码编写 |
| Trae2.1 | Deepseek 3.1 Terminus | 代码理解与生成模型,专注于代码逻辑分析 |
| Trae2.1 | Qwen3-coder | 阿里开发的代码生成模型,支持多种编程语言 |
| Trae2.1 | GLM-4.6 | 智谱AI的代码模型,具备优秀的代码理解能力 |
| Trae2.1 | Kimi-K2 | 月之暗面开发的代码模型,擅长长代码理解 |
评测结果
Cursor2.0模型注释结果
Sonet4.5注释示例与分析
package com.neusoft.aimate.text;
import java.util.ArrayList;
import java.util.List;
/**
* Markdown文档智能分割器 V3 Cursor Sonet4.5生成
*
* 主要功能:
* - 将长Markdown文档按照指定的最大长度进行智能分割
* - 保证分割后的每个块不超过最大长度限制
* - 保持Markdown结构的完整性(表格、代码块、列表等不会被随意截断)
* - 在分割时自动携带上下文标题,确保每个分块都有清晰的上下文
*
* 适用场景:
* - 文本向量化前的预处理(如RAG系统)
* - 大文档的分页显示
* - API调用时的内容长度限制
* - 文档索引和检索系统
*/
public class MarkdownSplitterV3 {
/**
* 分割Markdown文档的主方法
*
* 算法流程:
* 1. 按行解析Markdown文档
* 2. 识别不同类型的Markdown元素(标题、表格、代码块、列表、普通文本)
* 3. 针对每种元素类型采用特定的处理策略
* 4. 在长度超出限制时智能分割,并保持结构完整性
* 5. 分割时自动添加上下文标题
*
* @param markdown 待分割的Markdown文本内容
* @param maxlength 每个分块的最大字符长度(包括换行符)
* @return 分割后的文本块列表,每个块都是完整的Markdown片段
*/
public static List<String> splitMarkdown(String markdown, int maxlength) {
List<String> result = new ArrayList<>(); // 存储分割后的结果列表
StringBuilder currentBlock = new StringBuilder(); // 当前正在构建的文本块
String[] lines = markdown.split("\n"); // 按行分割Markdown文本
String currentTitle = ""; // 记录当前的标题行,用于在分割后保持上下文
int index = 0; // 当前处理的行索引
// 逐行遍历Markdown文档
while (index < lines.length) {
String line = lines[index];
// 情况1: 处理标题行(以#开头,如 # 标题、## 二级标题)
if (line.startsWith("#")) {
currentTitle = line; // 更新当前标题,用于后续分割时的上下文
// 检查添加标题后是否会超出长度限制
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock); // 保存当前块并重置
}
currentBlock.append(line).append("\n");
index++;
}
// 情况2: 处理表格(以|开头的行)
else if (line.startsWith("|")) {
// 表格需要特殊处理以保持表头和数据的完整性
index = processTable(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 情况3: 处理代码块(以```开头)
else if (line.startsWith("```")) {
// 代码块需要保持开始和结束标记的配对
index = processCodeBlock(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 情况4: 处理列表(数字列表如"1. "或无序列表如"- ")
else if (line.matches("^\\d+\\. ") || line.startsWith("- ")) {
// 列表项需要连续处理以保持列表的完整性
index = processList(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 情况5: 处理普通文本行
else {
// 只处理非空行,跳过空行
if(line.length() > 0) {
// 检查添加当前行后是否会超出长度限制
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock); // 保存当前块
}
currentBlock.append(line).append("\n");
}
index++;
}
}
// 处理最后一个文本块(如果还有内容未保存)
if (currentBlock.length() > 0) {
result.add(currentBlock.toString());
}
return result;
}
/**
* 判断是否需要分割当前块
*
* 判断逻辑:当前块长度 + 待添加行长度 + 换行符长度(1) > 最大长度限制
*
* @param currentBlock 当前正在构建的文本块
* @param line 待添加的行内容
* @param maxlength 最大长度限制
* @return 如果添加该行后会超出长度限制,返回true;否则返回false
*/
private static boolean shouldSplitBlock(StringBuilder currentBlock, String line, int maxlength) {
return currentBlock.length() + line.length() + 1 > maxlength; // +1是换行符的长度
}
/**
* 将当前块添加到结果列表中,并清空当前块以便构建下一个块
*
* @param result 结果列表,存储所有已完成的文本块
* @param currentBlock 当前文本块,将被添加到结果列表并清空
*/
private static void addCurrentBlockToResult(List<String> result, StringBuilder currentBlock) {
result.add(currentBlock.toString()); // 将当前块转为字符串并添加到结果列表
currentBlock.setLength(0); // 清空StringBuilder,相比new StringBuilder()更高效
}
/**
* 处理Markdown表格
*
* 表格结构:
* | 列1 | 列2 | 列3 | <- 表头
* |-----|-----|-----| <- 分隔行(必需)
* | 数据1 | 数据2 | 数据3 | <- 数据行
* | 数据4 | 数据5 | 数据6 | <- 数据行
*
* 处理策略:
* 1. 表头和分隔行必须一起保留
* 2. 如果表格整体能放入当前块,则整体添加
* 3. 如果表格过长,按行分割,但每个新块都要重复表头和分隔行
* 4. 如果是第一行数据就需要分割,说明当前块已经有其他内容,需要先删除表头再分割
*
* @param lines 所有行的数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题(用于新块的上下文)
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 表格开始的行索引
* @return 处理完表格后的行索引(指向表格后的下一行)
*/
private static int processTable(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
String tableHeader = lines[startIndex]; // 表头行,如:| 列1 | 列2 | 列3 |
int index = startIndex + 1;
String tableSeparator = "";
// 找到表格分隔行(如 |---|---|---|)
if (index < lines.length && isTableSeparator(lines[index])) {
tableSeparator = lines[index];
index++;
}
String fullTableHeader = tableHeader + "\n" + tableSeparator; // 完整的表头(包含分隔行)
boolean first = true; // 标记是否是第一行数据行
boolean needSplit = shouldSplitBlock(currentBlock, fullTableHeader, maxlength);
// 如果添加表头会超出长度限制,需要先分割当前块
if (needSplit) {
first = false;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n"); // 新块以标题开头,保持上下文
}
currentBlock.append(fullTableHeader).append("\n"); // 添加完整表头
// 逐行处理表格的数据行
while (index < lines.length && lines[index].startsWith("|")) {
String tableRow = lines[index];
// 如果添加当前数据行会超出长度限制
if (shouldSplitBlock(currentBlock, tableRow, maxlength)) {
// 如果是第一行数据就需要分割,说明当前块有其他内容
// 需要先删除刚添加的表头,让表格完整地出现在新块中
if (first) {
currentBlock.delete(currentBlock.length() - fullTableHeader.length() - 1, currentBlock.length() - 1);
}
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n"); // 新块添加标题
currentBlock.append(fullTableHeader).append("\n"); // 新块重新添加表头
}
currentBlock.append(tableRow).append("\n");
index++;
first = false; // 已经不是第一行了
}
// 如果当前块超出长度限制,保存它
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index; // 返回处理到的行索引
}
/**
* 判断一行是否是表格分隔符
*
* 合法的表格分隔符格式:
* - |---|---| 标准格式
* - | --- | --- | 带空格
* - |:---|:---:| 带对齐标记(左对齐:---、居中:---:、右对齐---:)
* - | :--- | :---: | ---: | 混合对齐
*
* 正则表达式解析:
* ^\\|? - 可选的起始竖线
* [ \\t]* - 可选的空格或制表符
* :?[-]+:? - 可选的冒号 + 一个或多个短横线 + 可选的冒号
* [ \\t]*\\| - 可选空格 + 竖线
* ([ \\t]*:?[-]+:?[ \\t]*\\|)* - 重复的列分隔符
* [ \\t]*$ - 行尾可选空格
*
* @param line 待判断的行
* @return 如果是合法的表格分隔符返回true,否则返回false
*/
private static boolean isTableSeparator(String line) {
return line.matches("^\\|?[ \\t]*:?[-]+:?[ \\t]*\\|([ \\t]*:?[-]+:?[ \\t]*\\|)*[ \\t]*$");
}
/**
* 处理Markdown代码块
*
* 代码块结构:
* ```java <- 开始标记(可选语言标识)
* public void test() {
* System.out.println("Hello");
* }
* ``` <- 结束标记
*
* 处理策略:
* 1. 代码块需要保持开始标记(```)和结束标记(```)的配对
* 2. 如果代码块能放入当前块,则整体添加
* 3. 如果代码块过长,需要分割时会破坏代码完整性(这是长度限制的妥协)
* 4. 分割时需要判断反引号数量,避免将代码内容中的```误认为结束标记
*
* @param lines 所有行的数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题(用于新块的上下文)
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 代码块开始的行索引
* @return 处理完代码块后的行索引(指向代码块后的下一行)
*/
private static int processCodeBlock(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = shouldSplitBlock(currentBlock, lines[index], maxlength);
// 如果添加代码块开始标记会超出长度限制,先分割当前块
if (needSplit) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n"); // 新块添加标题
}
currentBlock.append(lines[index]).append("\n"); // 添加代码块开始标记(如```java)
index++;
// 处理代码块内容,直到遇到结束标记(```)
// 条件说明:
// 1. !lines[index].startsWith("```") - 不是以```开头的行
// 2. countBackticks(lines[index]) % 2 != 0 - 或者反引号数量为奇数(说明不是真正的结束标记)
while (index < lines.length && (!lines[index].startsWith("```") || countBackticks(lines[index]) % 2 != 0)) {
String codeLine = lines[index];
// 如果代码块过长,需要分割(虽然会破坏代码块完整性,但这是长度限制的必要妥协)
if (shouldSplitBlock(currentBlock, codeLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(codeLine).append("\n");
index++;
}
// 添加代码块结束标记(```)
if (index < lines.length) {
String endLine = lines[index];
if (shouldSplitBlock(currentBlock, endLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(endLine).append("\n");
index++;
}
// 如果当前块超出长度限制,保存它
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 处理Markdown列表(有序列表和无序列表)
*
* 列表类型:
* 1. 有序列表:
* 1. 第一项
* 2. 第二项
* 3. 第三项
*
* 2. 无序列表:
* - 项目1
* - 项目2
* - 项目3
*
* 处理策略:
* 1. 连续的列表项作为一个整体处理
* 2. 如果列表能放入当前块,则整体添加
* 3. 如果列表过长,按项分割,每个新块添加标题
* 4. 如果列表没有被分割且不需要标题上下文,则移除开头的标题
*
* @param lines 所有行的数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题(用于新块的上下文)
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 列表开始的行索引
* @return 处理完列表后的行索引(指向列表后的下一行)
*/
private static int processList(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = false; // 标记是否发生了分割
// 处理连续的列表项
// 判断条件:以数字+点+空格开头(如"1. ")或以短横线+空格开头(如"- ")
while (index < lines.length && (lines[index].matches("^\\d+\\. ") || lines[index].startsWith("- "))) {
String listLine = lines[index];
// 如果添加当前列表项会超出长度限制
if (shouldSplitBlock(currentBlock, listLine, maxlength)) {
needSplit = true; // 标记发生了分割
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n"); // 新块以标题开头,保持上下文
}
currentBlock.append(listLine).append("\n");
index++;
}
// 优化:如果列表没有被分割且包含了标题,说明标题是多余的,删除它
// 这种情况发生在列表前刚好有一个标题,但列表完整地放入了当前块
if (!needSplit && currentBlock.length() > 0 && currentBlock.toString().contains(currentTitle + "\n")) {
currentBlock.delete(0, currentTitle.length() + 1);
}
// 如果当前块超出长度限制,保存它
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 计算字符串中反引号(`)的数量
*
* 用途:判断代码块的开始和结束标记
* - 正常的代码块标记:```(3个反引号,偶数次包含)
* - 代码中的反引号:可能是奇数个,不应该被视为结束标记
*
* 示例:
* "```java" -> 3个反引号
* "```" -> 3个反引号
* "let x = `hello`" -> 2个反引号
*
* @param line 待统计的行
* @return 反引号的数量
*/
private static int countBackticks(String line) {
int count = 0;
for (char c : line.toCharArray()) {
if (c == '`') {
count++;
}
}
return count;
}
}
Sonet4.5生成的代码注释在整体表现上堪称典范。以类注释为例,它清晰列出了核心功能(如"将长Markdown文档按照指定的最大长度进行智能分割")和四大适用场景(如"文本向量化前的预处理"),准确反映了代码设计意图,在准确性维度(权重30%)可得满分5分。
在完整性与信息量(权重25%)方面,注释覆盖了关键逻辑。例如processTable方法的注释详细说明了表格处理策略:"表头和分隔行必须一起保留"并解释了分割时重复表头的机制。但正如备注所指,它未明确提及空表格或格式错误表格的边界处理,不过由于主要逻辑均已覆盖,仍给予5分评价。
清晰度与可读性(权重20%)表现突出。splitMarkdown方法的注释采用编号列表形式呈现算法流程:“1. 按行解析Markdown文档\n2. 识别不同类型的Markdown元素…”,这种结构化描述极大提升了可读性,获得5分。
实用性与辅助作用(权重15%)方面,注释提供了具体的使用指导。如isTableSeparator方法注释中通过正则表达式解析和格式示例(“|—|—|”、“|:—|:—😐”)帮助开发者理解表格分隔符判断逻辑,虽然未深入性能优化建议,但实用价值显著,评为5分。
一致性(权重10%)贯穿始终,所有方法注释均采用统一的参数-返回值-功能说明结构,变量注释风格一致(如currentBlock的"当前正在构建的文本块"),符合规范要求,获得5分。
Composer注释示例与分析
package com.neusoft.aimate.text;
import java.util.ArrayList;
import java.util.List;
/**
* Markdown文档分割器 V4 Cousor composer生成
*
* 用于将长Markdown文档按照指定的最大长度进行智能分割,
* 保证分割后的每个块不超过最大长度,同时尽可能保持Markdown结构的完整性。
*
* 功能特性:
* - 支持标题、表格、代码块、列表等Markdown元素的智能识别和处理
* - 在分割时自动保留上下文信息(如标题)
* - 尽可能保持Markdown元素(如表格、代码块)的完整性
*/
public class MarkdownSplitterV4 {
/**
* 分割Markdown文档的主方法
*
* @param markdown 待分割的Markdown文本内容
* @param maxlength 每个分块的最大长度(字符数)
* @return 分割后的文本块列表,每个块都不超过maxlength
*/
public static List<String> splitMarkdown(String markdown, int maxlength) {
List<String> result = new ArrayList<>(); // 存储分割后的结果块
StringBuilder currentBlock = new StringBuilder(); // 当前正在构建的文本块
String[] lines = markdown.split("\n"); // 按换行符分割成行数组
String currentTitle = ""; // 记录当前的标题,用于在分割后保持上下文
int index = 0; // 当前处理的行索引
// 遍历所有行进行处理
while (index < lines.length) {
String line = lines[index];
// 处理标题行(以#开头的行)
if (line.startsWith("#")) {
currentTitle = line; // 更新当前标题
// 如果添加标题后会超出长度限制,先保存当前块
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
index++;
}
// 处理表格(以|开头的行)
else if (line.startsWith("|")) {
index = processTable(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理代码块(以```开头的行)
else if (line.startsWith("```")) {
index = processCodeBlock(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理列表(有序列表:数字. 或无序列表:-)
else if (line.matches("^\\d+\\. ") || line.startsWith("- ")) {
index = processList(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理普通文本行
else {
// 只处理非空行,空行会被忽略
if(line.length() > 0) {
// 如果添加当前行会超出长度限制,先保存当前块
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
}
index++;
}
}
// 处理最后一个块(如果还有未保存的内容)
if (currentBlock.length() > 0) {
result.add(currentBlock.toString());
}
return result;
}
/**
* 判断是否需要分割当前块
*
* 当添加新的一行内容后,如果总长度会超过最大限制,则需要分割
*
* @param currentBlock 当前正在构建的文本块
* @param line 待添加的新行内容
* @param maxlength 最大长度限制
* @return 如果添加该行后会超出长度限制,返回true;否则返回false
*/
private static boolean shouldSplitBlock(StringBuilder currentBlock, String line, int maxlength) {
// +1 是换行符的长度
return currentBlock.length() + line.length() + 1 > maxlength;
}
/**
* 将当前块添加到结果列表中,并清空当前块以便构建新的块
*
* @param result 结果列表
* @param currentBlock 当前文本块
*/
private static void addCurrentBlockToResult(List<String> result, StringBuilder currentBlock) {
result.add(currentBlock.toString());
currentBlock.setLength(0); // 清空StringBuilder,保留容量以提高性能
}
/**
* 处理Markdown表格
*
* 表格结构:
* | 表头1 | 表头2 |
* |---|---| (分隔行)
* | 数据1 | 数据2 | (数据行)
*
* 处理策略:
* - 保持表头和分隔行的完整性
* - 如果表格过长,可以在数据行之间分割,但每个新块都会包含完整的表头
*
* @param lines 所有行的数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题(用于在分割后保持上下文)
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 表格开始的行索引
* @return 处理完表格后的行索引(下一行应该处理的索引)
*/
private static int processTable(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
String tableHeader = lines[startIndex]; // 表头行
int index = startIndex + 1;
String tableSeparator = ""; // 表格分隔行
// 查找并提取分隔行(如:|---|---|)
if (index < lines.length && isTableSeparator(lines[index])) {
tableSeparator = lines[index];
index++;
}
// 完整的表头包含表头行和分隔行
String fullTableHeader = tableHeader + "\n" + tableSeparator;
boolean first = true; // 标记是否是第一行数据
boolean needSplit = shouldSplitBlock(currentBlock, fullTableHeader, maxlength);
// 如果添加表头会超出长度限制,需要先分割
if (needSplit) {
first = false;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n"); // 新块以标题开头,保持上下文
}
currentBlock.append(fullTableHeader).append("\n");
// 处理表格的数据行(所有以|开头的行)
while (index < lines.length && lines[index].startsWith("|")) {
String tableRow = lines[index];
// 如果添加当前数据行会超出长度限制
if (shouldSplitBlock(currentBlock, tableRow, maxlength)) {
// 如果是第一行且需要分割,删除刚添加的表头(因为当前块放不下)
if (first) {
currentBlock.delete(currentBlock.length() - fullTableHeader.length() - 1, currentBlock.length() - 1);
}
// 保存当前块并开始新块
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
currentBlock.append(fullTableHeader).append("\n"); // 在新块中重新添加表头
}
currentBlock.append(tableRow).append("\n");
index++;
first = false; // 已处理过数据行,不再是第一行
}
// 如果处理完表格后当前块仍然超出长度限制,保存它
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 判断一行是否是表格分隔符
*
* 表格分隔符的格式如:|---|---| 或 | :--- | :---: |
* 正则表达式说明:
* ^\\|? - 可选的开头 |
* [ \\t]* - 可选的空格或制表符
* :?[-]+:? - 一个或多个连字符,两端可选的冒号(用于对齐)
* [ \\t]*\\| - 可选空格后跟 |
* (...) - 重复上述模式
*
* @param line 待判断的行
* @return 如果是表格分隔符返回true,否则返回false
*/
private static boolean isTableSeparator(String line) {
return line.matches("^\\|?[ \\t]*:?[-]+:?[ \\t]*\\|([ \\t]*:?[-]+:?[ \\t]*\\|)*[ \\t]*$");
}
/**
* 处理Markdown代码块
*
* 代码块结构:
* ```
* 代码内容
* ```
*
* 处理策略:
* - 尽量保持代码块的完整性
* - 如果代码块过长,可以在代码行之间分割,但会破坏代码块的完整性
* - 注意处理代码中包含```的情况(使用countBackticks判断)
*
* @param lines 所有行的数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题(用于在分割后保持上下文)
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 代码块开始的行索引(包含```的行)
* @return 处理完代码块后的行索引
*/
private static int processCodeBlock(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = shouldSplitBlock(currentBlock, lines[index], maxlength);
// 如果添加代码块开始标记会超出长度限制,先分割
if (needSplit) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(lines[index]).append("\n"); // 添加代码块开始标记(```)
index++;
// 处理代码块内容,直到遇到结束标记(```)
// 注意:需要处理代码中包含反引号的情况,使用countBackticks判断是否为真正的结束标记
while (index < lines.length && (!lines[index].startsWith("```") || countBackticks(lines[index]) % 2 != 0)) {
String codeLine = lines[index];
// 如果代码块过长,需要分割(虽然会破坏代码块完整性,但这是长度限制的妥协)
if (shouldSplitBlock(currentBlock, codeLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(codeLine).append("\n");
index++;
}
// 添加代码块结束标记(```)
if (index < lines.length) {
String endLine = lines[index];
if (shouldSplitBlock(currentBlock, endLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(endLine).append("\n");
index++;
}
// 如果处理完代码块后当前块仍然超出长度限制,保存它
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 处理Markdown列表
*
* 支持两种列表格式:
* 1. 有序列表:以数字和点开头,如 "1. 列表项"
* 2. 无序列表:以"- "开头,如 "- 列表项"
*
* 处理策略:
* - 连续处理所有列表项
* - 如果列表过长,可以在列表项之间分割
* - 如果列表没有被分割,且块中已包含标题,则删除重复的标题
*
* @param lines 所有行的数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题(用于在分割后保持上下文)
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 列表开始的行索引
* @return 处理完列表后的行索引
*/
private static int processList(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = false; // 标记列表是否被分割过
// 处理连续的列表项(有序或无序列表)
while (index < lines.length && (lines[index].matches("^\\d+\\. ") || lines[index].startsWith("- "))) {
String listLine = lines[index];
// 如果添加列表项会超出长度限制
if (shouldSplitBlock(currentBlock, listLine, maxlength)) {
needSplit = true;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n"); // 新块以标题开头
}
currentBlock.append(listLine).append("\n");
index++;
}
// 如果列表没有被分割且当前块中包含了重复的标题,删除开头的标题
// 这是为了避免在不必要的情况下添加标题
if (!needSplit && currentBlock.length() > 0 && currentBlock.toString().contains(currentTitle + "\n")) {
currentBlock.delete(0, currentTitle.length() + 1);
}
// 如果处理完列表后当前块仍然超出长度限制,保存它
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 计算字符串中反引号(`)的数量
*
* 用于判断代码块的开始和结束标记。
* 因为代码内容中可能包含反引号,所以需要判断一行中的```是否是真正的代码块结束标记。
* 如果反引号数量是偶数,则可能是代码内容中的反引号,不是结束标记。
*
* @param line 待统计的行
* @return 反引号的数量
*/
private static int countBackticks(String line) {
int count = 0;
for (char c : line.toCharArray()) {
if (c == '`') {
count++;
}
}
return count;
}
}
Composer模型生成的注释展现了显著的深度和实用性。在MarkdownSplitterV4类的注释中,不仅完整描述了类的核心功能(“将长Markdown文档按照指定的最大长度进行智能分割”),还通过"功能特性"列表具体说明了支持的Markdown元素类型。与方法级注释相比,Composer在关键方法中嵌入了丰富的示例说明:
在processTable方法注释中,详细展示了表格结构示例:
| 表头1 | 表头2 |
|---|---|
| 数据1 | 数据2 |
并解释了分隔行的正则表达式匹配规则。类似地,isTableSeparator方法注释中直接给出了分隔行的具体格式示例(|---|---|和| :--- | :---: |),这种实例化说明让开发者能快速理解复杂的正则逻辑。
与Sonet4.5生成的注释相比,Composer的独特优势体现在三个方面:首先,注释深度超越基础功能描述,如在processCodeBlock中特别说明"需要处理代码中包含反引号的情况"这种边界场景;其次,示例丰富度更高,在六个核心方法中都嵌入了结构示例或正则模式示例;最后,虽然未提供独立的使用示例代码段,但通过内嵌的结构示例实现了同等效果。
这些注释对代码理解的支持程度显著提升,特别是在处理复杂Markdown元素时,开发者能通过注释中的示例快速掌握表格、代码块的分割策略,避免了直接阅读正则表达式或循环逻辑的理解成本。这种"示例驱动"的注释风格,使得即使不熟悉Markdown解析的开发者也能准确把握代码行为边界。
Trae2.10模型注释结果
Deepseek 3.1 Terminus注释示例与分析
package com.neusoft.aimate.text;
import java.util.ArrayList;
import java.util.List;
/**
* Markdown文档分割器V5版本 Trae-DS31
* 用于将Markdown文档按照特定规则分割成多个块,便于后续处理
*
* 主要功能:
* 1. 支持标题、表格、代码块、列表等Markdown元素的智能分割
* 2. 根据最大长度限制自动分割长文本
* 3. 保持Markdown结构的完整性
*
* @author AIMate Team
* @version 5.0
*/
public class MarkdownSplitterV5 {
/**
* 分割Markdown文档的主要方法
*
* @param markdown 原始Markdown文档内容
* @param maxlength 每个分割块的最大长度限制
* @return 分割后的Markdown块列表
*/
public static List<String> splitMarkdown(String markdown, int maxlength) {
List<String> result = new ArrayList<>();
StringBuilder currentBlock = new StringBuilder();
String[] lines = markdown.split("\n");
String currentTitle = ""; // 当前标题,用于保持文档结构
int index = 0;
// 逐行处理Markdown文档
while (index < lines.length) {
String line = lines[index];
// 处理标题行(以#开头)
if (line.startsWith("#")) {
currentTitle = line;
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
index++;
}
// 处理表格行(以|开头)
else if (line.startsWith("|")) {
index = processTable(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理代码块(以```开头)
else if (line.startsWith("```")) {
index = processCodeBlock(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理列表项(以数字.或-开头)
else if (line.matches("^\\d+\\. ") || line.startsWith("- ")) {
index = processList(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理普通文本行
else {
if(line.length() > 0) {
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
}
index++;
}
}
// 处理最后一个未完成的块
if (currentBlock.length() > 0) {
result.add(currentBlock.toString());
}
return result;
}
/**
* 判断当前块是否需要分割
*
* @param currentBlock 当前正在构建的文本块
* @param line 将要添加的新行
* @param maxlength 最大长度限制
* @return 如果需要分割返回true,否则返回false
*/
private static boolean shouldSplitBlock(StringBuilder currentBlock, String line, int maxlength) {
return currentBlock.length() + line.length() + 1 > maxlength;
}
/**
* 将当前块添加到结果列表中并清空当前块
*
* @param result 结果列表
* @param currentBlock 当前文本块
*/
private static void addCurrentBlockToResult(List<String> result, StringBuilder currentBlock) {
result.add(currentBlock.toString());
currentBlock.setLength(0);
}
/**
* 处理表格内容
*
* @param lines 所有行数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的索引位置
* @return 处理完成后的索引位置
*/
private static int processTable(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
String tableHeader = lines[startIndex]; // 表头行
int index = startIndex + 1;
String tableSeparator = ""; // 表格分隔符行
// 查找表格分隔符行(通常是第二行)
if (index < lines.length && isTableSeparator(lines[index])) {
tableSeparator = lines[index];
index++;
}
String fullTableHeader = tableHeader + "\n" + tableSeparator;
boolean first = true; // 标记是否为表格的第一行处理
// 检查是否需要分割当前块
boolean needSplit = shouldSplitBlock(currentBlock, fullTableHeader, maxlength);
if (needSplit) {
first = false;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(fullTableHeader).append("\n");
// 处理表格数据行
while (index < lines.length && lines[index].startsWith("|")) {
String tableRow = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, tableRow, maxlength)) {
if (first) {
// 如果是第一行,需要删除之前添加的表头
currentBlock.delete(currentBlock.length()-fullTableHeader.length()-1, currentBlock.length() -1);
}
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
currentBlock.append(fullTableHeader).append("\n");
}
currentBlock.append(tableRow).append("\n");
index++;
first = false;
}
// 检查当前块是否超过最大长度
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 判断是否为表格分隔符行
*
* @param line 待检查的行
* @return 如果是表格分隔符返回true,否则返回false
*/
private static boolean isTableSeparator(String line) {
return line.matches("^\\|?[ \\t]*:?[-]+:?[ \\t]*\\|([ \\t]*:?[-]+:?[ \\t]*\\|)*[ \\t]*$");
}
/**
* 处理代码块内容
*
* @param lines 所有行数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的索引位置
* @return 处理完成后的索引位置
*/
private static int processCodeBlock(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
// 检查是否需要分割当前块
boolean needSplit = shouldSplitBlock(currentBlock, lines[index], maxlength);
if (needSplit) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(lines[index]).append("\n");
index++;
// 处理代码块内的所有行,直到遇到结束标记
while (index < lines.length && (!lines[index].startsWith("```") || countBackticks(lines[index]) % 2 != 0)) {
String codeLine = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, codeLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(codeLine).append("\n");
index++;
}
// 处理代码块结束标记
if (index < lines.length) {
String endLine = lines[index];
if (shouldSplitBlock(currentBlock, endLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(endLine).append("\n");
index++;
}
// 检查当前块是否超过最大长度
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 处理列表内容
*
* @param lines 所有行数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的索引位置
* @return 处理完成后的索引位置
*/
private static int processList(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = false;
// 处理连续的列表项
while (index < lines.length && (lines[index].matches("^\\d+\\. ") || lines[index].startsWith("- "))) {
String listLine = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, listLine, maxlength)) {
needSplit = true;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(listLine).append("\n");
index++;
}
// 如果没有分割且当前块包含标题,则删除重复的标题
if (!needSplit && currentBlock.length() > 0 && currentBlock.toString().contains(currentTitle + "\n")) {
currentBlock.delete(0, currentTitle.length() + 1);
}
// 检查当前块是否超过最大长度
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 统计行中反引号的数量
*
* @param line 待统计的行
* @return 反引号的数量
*/
private static int countBackticks(String line) {
int count = 0;
for (char c : line.toCharArray()) {
if (c == '`') {
count++;
}
}
return count;
}
}
Deepseek 3.1 Terminus生成的注释体现了典型的精炼风格。以类注释为例:
/**
* Markdown文档分割器V5版本 Trae-DS31
* 用于将Markdown文档按照特定规则分割成多个块,便于后续处理
*
* 主要功能:
* 1. 支持标题、表格、代码块、列表等Markdown元素的智能分割
* 2. 根据最大长度限制自动分割长文本
* 3. 保持Markdown结构的完整性
*/
这段注释仅用三行核心描述和三个功能点就完整概括了类的设计目标,没有冗余的修饰词。方法注释同样简洁,如shouldSplitBlock方法的注释:
/**
* 判断当前块是否需要分割
*
* @param currentBlock 当前正在构建的文本块
* @param line 将要添加的新行
* @param maxlength 最大长度限制
* @return 如果需要分割返回true,否则返回false
*/
仅用一句话准确点明方法用途,参数说明直接对应代码实现。在理解准确性方面,模型能精准捕捉代码逻辑,例如processTable方法注释中"处理表格内容"的描述与代码中处理表头、分隔符和数据行的实际逻辑完全匹配。这种注释风格既保证了开发人员快速理解代码意图,又避免了过度描述带来的阅读负担,符合高效协作的需求。
Qwen3-coder注释示例与分析
package com.neusoft.aimate.text;
import java.util.ArrayList;
import java.util.List;
/**
* Markdown文档分割器V6版本 Trae-Qwen3Code
* 用于将Markdown文档按照特定规则分割成多个块,便于后续处理
*
* 主要功能:
* 1. 支持标题、表格、代码块、列表等Markdown元素的智能分割
* 2. 根据最大长度限制自动分割长文本
* 3. 保持Markdown结构的完整性
*
* @author AIMate Team
* @version 6.0
*/
public class MarkdownSplitterV6 {
/**
* 分割Markdown文档的主要方法
*
* @param markdown 原始Markdown文档内容
* @param maxlength 每个分割块的最大长度限制
* @return 分割后的Markdown块列表
*/
public static List<String> splitMarkdown(String markdown, int maxlength) {
List<String> result = new ArrayList<>();
StringBuilder currentBlock = new StringBuilder();
String[] lines = markdown.split("\n");
String currentTitle = ""; // 当前标题,用于保持文档结构
int index = 0;
// 逐行处理Markdown文档
while (index < lines.length) {
String line = lines[index];
// 处理标题行(以#开头)
if (line.startsWith("#")) {
currentTitle = line;
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
index++;
}
// 处理表格行(以|开头)
else if (line.startsWith("|")) {
index = processTable(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理代码块(以```开头)
else if (line.startsWith("```")) {
index = processCodeBlock(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理列表项(以数字.或-开头)
else if (line.matches("^\\d+\\. ") || line.startsWith("- ")) {
index = processList(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理普通文本行
else {
if(line.length()>0) {
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
}
index++;
}
}
// 处理最后一个未完成的块
if (currentBlock.length() > 0) {
result.add(currentBlock.toString());
}
return result;
}
/**
* 判断当前块是否需要分割
*
* @param currentBlock 当前正在构建的文本块
* @param line 将要添加的新行
* @param maxlength 最大长度限制
* @return 如果需要分割返回true,否则返回false
*/
private static boolean shouldSplitBlock(StringBuilder currentBlock, String line, int maxlength) {
return currentBlock.length() + line.length() + 1 > maxlength;
}
/**
* 将当前块添加到结果列表中并清空当前块
*
* @param result 结果列表
* @param currentBlock 当前文本块
*/
private static void addCurrentBlockToResult(List<String> result, StringBuilder currentBlock) {
result.add(currentBlock.toString());
currentBlock.setLength(0);
}
/**
* 处理表格内容
*
* @param lines 所有行数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的索引位置
* @return 处理完成后的索引位置
*/
private static int processTable(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
String tableHeader = lines[startIndex]; // 表头行
int index = startIndex + 1;
String tableSeparator = ""; // 表格分隔符行
// 查找表格分隔符行(通常是第二行)
if (index < lines.length && isTableSeparator(lines[index])) {
tableSeparator = lines[index];
index++;
}
String fullTableHeader = tableHeader + "\n" + tableSeparator;
boolean first = true; // 标记是否为表格的第一行处理
// 检查是否需要分割当前块
boolean needSplit = shouldSplitBlock(currentBlock, fullTableHeader, maxlength);
if (needSplit) {
first = false;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(fullTableHeader).append("\n");
// 处理表格数据行
while (index < lines.length && lines[index].startsWith("|")) {
String tableRow = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, tableRow, maxlength)) {
if (first) {
// 如果是第一行,需要删除之前添加的表头
currentBlock.delete(currentBlock.length()-fullTableHeader.length()-1, currentBlock.length() -1);
}
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
currentBlock.append(fullTableHeader).append("\n");
}
currentBlock.append(tableRow).append("\n");
index++;
first = false;
}
// 检查当前块是否超过最大长度
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 判断是否为表格分隔符行
*
* @param line 待检查的行
* @return 如果是表格分隔符返回true,否则返回false
*/
private static boolean isTableSeparator(String line) {
return line.matches("^\\|?[ \\t]*:?[-]+:?[ \\t]*\\|([ \\t]*:?[-]+:?[ \\t]*\\|)*[ \\t]*$");
}
/**
* 处理代码块内容
*
* @param lines 所有行数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的索引位置
* @return 处理完成后的索引位置
*/
private static int processCodeBlock(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
// 检查是否需要分割当前块
boolean needSplit = shouldSplitBlock(currentBlock, lines[index], maxlength);
if (needSplit) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(lines[index]).append("\n");
index++;
// 处理代码块内的所有行,直到遇到结束标记
while (index < lines.length && (!lines[index].startsWith("```") || countBackticks(lines[index]) % 2 != 0)) {
String codeLine = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, codeLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(codeLine).append("\n");
index++;
}
// 处理代码块结束标记
if (index < lines.length) {
String endLine = lines[index];
if (shouldSplitBlock(currentBlock, endLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(endLine).append("\n");
index++;
}
// 检查当前块是否超过最大长度
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 处理列表内容
*
* @param lines 所有行数组
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的索引位置
* @return 处理完成后的索引位置
*/
private static int processList(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = false;
// 处理连续的列表项
while (index < lines.length && (lines[index].matches("^\\d+\\. ") || lines[index].startsWith("- "))) {
String listLine = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, listLine, maxlength)) {
needSplit = true;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(listLine).append("\n");
index++;
}
// 如果没有分割且当前块包含标题,则删除重复的标题
if (!needSplit && currentBlock.length() > 0 && currentBlock.toString().contains(currentTitle + "\n")) {
currentBlock.delete(0, currentTitle.length() + 1);
}
// 检查当前块是否超过最大长度
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 统计行中反引号的数量
*
* @param line 待统计的行
* @return 反引号的数量
*/
private static int countBackticks(String line) {
int count = 0;
for (char c : line.toCharArray()) {
if (c == '`') {
count++;
}
}
return count;
}
}
Qwen3-coder生成的注释示例中,类注释以清晰的结构描述了整体功能:
/**
* Markdown文档分割器V6版本 Trae-Qwen3Code
* 用于将Markdown文档按照特定规则分割成多个块,便于后续处理
*
* 主要功能:
* 1. 支持标题、表格、代码块、列表等Markdown元素的智能分割
* 2. 根据最大长度限制自动分割长文本
* 3. 保持Markdown结构的完整性
*
* @author AIMate Team
* @version 6.0
*/
方法注释同样精炼,例如splitMarkdown方法的说明:
/**
* 分割Markdown文档的主要方法
*
* @param markdown 原始Markdown文档内容
* @param maxlength 每个分割块的最大长度限制
* @return 分割后的Markdown块列表
*/
在语言流畅度上,Qwen3-coder的注释采用自然的中文表达,术语准确(如“智能分割”“结构完整性”),逻辑连贯。结构清晰度突出,通过分点列举核心功能,参数和返回值说明简洁明确,无冗余描述。
与其他Trae模型(如Deepseek、GLM-4.6)相比,Qwen3-coder延续了Trae系列普遍精炼的风格,注释均聚焦于核心逻辑,避免展开具体示例。但差异在于:Qwen3-coder的注释结构更规整,例如类注释中明确列出功能点,而其他Trae模型可能仅用单句概括。这种一致性体现在精炼性上——所有Trae模型均以“达到开发标准”为前提,用最少文字覆盖关键信息,未出现Cursor模型中常见的详细示例或扩展说明。
GLM-4.6注释示例与分析
package com.neusoft.aimate.text;
import java.util.ArrayList;
import java.util.List;
/**
* Markdown文档分割器V7版本 Trae-GLM4.6
* 用于将Markdown文档按照特定规则分割成多个块,便于后续处理
* 支持标题、表格、代码块、列表等Markdown元素的智能分割
*
* @version V7
* @author AI Assistant
*/
public class MarkdownSplitterV7 {
/**
* 将Markdown文档按照特定规则分割成多个块
*
* @param markdown 要分割的Markdown文本
* @param maxlength 每个块的最大长度
* @return 分割后的文本块列表
*/
public static List<String> splitMarkdown(String markdown, int maxlength) {
List<String> result = new ArrayList<>();
StringBuilder currentBlock = new StringBuilder();
String[] lines = markdown.split("\n");
String currentTitle = "";
int index = 0;
// 逐行处理Markdown内容
while (index < lines.length) {
String line = lines[index];
// 处理标题行
if (line.startsWith("#")) {
currentTitle = line;
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
index++;
}
// 处理表格
else if (line.startsWith("|")) {
index = processTable(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理代码块
else if (line.startsWith("```")) {
index = processCodeBlock(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理列表
else if (line.matches("^\\d+\\. ") || line.startsWith("- ")) {
index = processList(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理普通文本行
else {
if(line.length()>0) {
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
}
index++;
}
}
// 添加最后一个块
if (currentBlock.length() > 0) {
result.add(currentBlock.toString());
}
return result;
}
/**
* 判断当前块是否需要分割
*
* @param currentBlock 当前块内容
* @param line 要添加的行
* @param maxlength 最大长度限制
* @return 如果需要分割返回true,否则返回false
*/
private static boolean shouldSplitBlock(StringBuilder currentBlock, String line, int maxlength) {
return currentBlock.length() + line.length() + 1 > maxlength;
}
/**
* 将当前块添加到结果列表中,并清空当前块
*
* @param result 结果列表
* @param currentBlock 当前块
*/
private static void addCurrentBlockToResult(List<String> result, StringBuilder currentBlock) {
result.add(currentBlock.toString());
currentBlock.setLength(0);
}
/**
* 处理表格内容
*
* @param lines 所有行
* @param currentBlock 当前块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始索引
* @return 处理结束后的索引
*/
private static int processTable(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
String tableHeader = lines[startIndex];
int index = startIndex + 1;
String tableSeparator = "";
// 找到分隔行
if (index < lines.length && isTableSeparator(lines[index])) {
tableSeparator = lines[index];
index++;
}
String fullTableHeader = tableHeader + "\n" + tableSeparator;
boolean first = true;
boolean needSplit = shouldSplitBlock(currentBlock, fullTableHeader, maxlength);
if (needSplit) {
first = false;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(fullTableHeader).append("\n");
// 处理表格行
while (index < lines.length && lines[index].startsWith("|")) {
String tableRow = lines[index];
if (shouldSplitBlock(currentBlock, tableRow, maxlength)) {
if (first) {
currentBlock.delete(currentBlock.length()-fullTableHeader.length()-1, currentBlock.length() -1);
}
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
currentBlock.append(fullTableHeader).append("\n");
}
currentBlock.append(tableRow).append("\n");
index++;
first = false;
}
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 判断是否为表格分隔行
*
* @param line 要检查的行
* @return 如果是表格分隔行返回true,否则返回false
*/
private static boolean isTableSeparator(String line) {
return line.matches("^\\|?[ \\t]*:?[-]+:?[ \\t]*\\|([ \\t]*:?[-]+:?[ \\t]*\\|)*[ \\t]*$");
}
/**
* 处理代码块内容
*
* @param lines 所有行
* @param currentBlock 当前块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始索引
* @return 处理结束后的索引
*/
private static int processCodeBlock(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = shouldSplitBlock(currentBlock, lines[index], maxlength);
if (needSplit) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(lines[index]).append("\n");
index++;
// 处理代码块内容,直到遇到结束标记
while (index < lines.length && (!lines[index].startsWith("```") || countBackticks(lines[index]) % 2 != 0)) {
String codeLine = lines[index];
if (shouldSplitBlock(currentBlock, codeLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(codeLine).append("\n");
index++;
}
// 处理代码块结束标记
if (index < lines.length) {
String endLine = lines[index];
if (shouldSplitBlock(currentBlock, endLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(endLine).append("\n");
index++;
}
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 处理列表内容
*
* @param lines 所有行
* @param currentBlock 当前块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始索引
* @return 处理结束后的索引
*/
private static int processList(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = false;
// 处理所有连续的列表项
while (index < lines.length && (lines[index].matches("^\\d+\\. ") || lines[index].startsWith("- "))) {
String listLine = lines[index];
if (shouldSplitBlock(currentBlock, listLine, maxlength)) {
needSplit = true;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(listLine).append("\n");
index++;
}
// 如果不需要分割且当前块包含标题,则移除标题
if (!needSplit && currentBlock.length() > 0 && currentBlock.toString().contains(currentTitle + "\n")) {
currentBlock.delete(0, currentTitle.length() + 1);
}
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 计算字符串中反引号的数量
*
* @param line 要检查的字符串
* @return 反引号的数量
*/
private static int countBackticks(String line) {
int count = 0;
for (char c : line.toCharArray()) {
if (c == '`') {
count++;
}
}
return count;
}
}
GLM-4.6生成的注释体现了典型的精炼风格,在保留关键信息的同时避免冗余。类级别注释清晰概括了核心功能:“用于将Markdown文档按照特定规则分割成多个块,便于后续处理;支持标题、表格、代码块、列表等Markdown元素的智能分割”,仅用三句话就完整说明了工具的主要用途和特性。
方法注释同样简洁有力。如splitMarkdown方法的注释准确描述了"将Markdown文档按照特定规则分割成多个块",并明确标注了输入参数"markdown-要分割的Markdown文本"和"maxlength-每个块的最大长度",以及返回值"分割后的文本块列表"。这种注释方式让开发者能够快速把握方法的核心作用,而不过度陷入细节。
在实用性方面,GLM-4.6的注释对开发者十分友好。私有方法的注释如shouldSplitBlock的"判断当前块是否需要分割"和processTable的"处理表格内容",采用直白的语言描述功能,配合参数说明,使得代码逻辑一目了然。这种注释风格特别适合快速代码审查和新人上手,开发者无需深入阅读方法实现就能理解其基本逻辑。
值得注意的是,虽然注释精简,但关键的技术细节都得到了保留。例如isTableSeparator方法通过正则表达式判断表格分隔行,注释准确指出了这一技术特征。这种平衡精炼与信息完整性的做法,既避免了注释臃肿,又确保了开发效率。
Kimi-K2注释示例与分析
package com.neusoft.aimate.text;
import java.util.ArrayList;
import java.util.List;
/**
* Markdown文本分割器V8版本 Trae-KimiK2
* 用于将长Markdown文本按照指定最大长度分割成多个块,同时保持文档结构的完整性
*
* 主要功能:
* 1. 按标题、表格、代码块、列表等Markdown元素进行智能分割
* 2. 保持文档结构的完整性,避免在不当位置分割
* 3. 支持自定义最大块长度
*
* @author AI助手
* @version 8.0
*/
public class MarkdownSplitterV8 {
/**
* 将Markdown文本分割成多个块
*
* @param markdown 原始Markdown文本
* @param maxlength 每个块的最大长度限制
* @return 分割后的文本块列表
*/
public static List<String> splitMarkdown(String markdown, int maxlength) {
List<String> result = new ArrayList<>();
StringBuilder currentBlock = new StringBuilder();
String[] lines = markdown.split("\n");
String currentTitle = "";
int index = 0;
// 遍历每一行进行处理
while (index < lines.length) {
String line = lines[index];
// 处理标题行(以#开头)
if (line.startsWith("#")) {
currentTitle = line;
// 检查是否需要分割当前块
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
index++;
}
// 处理表格行(以|开头)
else if (line.startsWith("|")) {
index = processTable(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理代码块(以```开头)
else if (line.startsWith("```")) {
index = processCodeBlock(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理列表项(数字列表或无序列表)
else if (line.matches("^\\d+\\. ") || line.startsWith("- ")) {
index = processList(lines, currentBlock, currentTitle, result, maxlength, index);
}
// 处理普通文本行
else {
// 只处理非空行
if(line.length() > 0) {
// 检查是否需要分割当前块
if (shouldSplitBlock(currentBlock, line, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
}
currentBlock.append(line).append("\n");
}
index++;
}
}
// 处理剩余的文本块
if (currentBlock.length() > 0) {
result.add(currentBlock.toString());
}
return result;
}
/**
* 判断是否需要分割当前块
*
* @param currentBlock 当前文本块
* @param line 要添加的新行
* @param maxlength 最大长度限制
* @return 如果需要分割返回true,否则返回false
*/
private static boolean shouldSplitBlock(StringBuilder currentBlock, String line, int maxlength) {
return currentBlock.length() + line.length() + 1 > maxlength;
}
/**
* 将当前块添加到结果列表中,并清空当前块
*
* @param result 结果列表
* @param currentBlock 当前文本块
*/
private static void addCurrentBlockToResult(List<String> result, StringBuilder currentBlock) {
result.add(currentBlock.toString());
currentBlock.setLength(0);
}
/**
* 处理Markdown表格
* 表格需要特殊处理以保持其结构完整性
*
* @param lines 所有文本行
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的行索引
* @return 处理完表格后的下一行索引
*/
private static int processTable(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
String tableHeader = lines[startIndex];
int index = startIndex + 1;
String tableSeparator = "";
// 找到表格的分隔行(通常是第二行)
if (index < lines.length && isTableSeparator(lines[index])) {
tableSeparator = lines[index];
index++;
}
String fullTableHeader = tableHeader + "\n" + tableSeparator;
boolean first = true;
boolean needSplit = shouldSplitBlock(currentBlock, fullTableHeader, maxlength);
// 如果需要分割,先保存当前块并开始新块
if (needSplit) {
first = false;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(fullTableHeader).append("\n");
// 处理表格的剩余行
while (index < lines.length && lines[index].startsWith("|")) {
String tableRow = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, tableRow, maxlength)) {
// 如果是第一个表格行,需要删除之前添加的表头
if (first) {
currentBlock.delete(currentBlock.length() - fullTableHeader.length() - 1, currentBlock.length() - 1);
}
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
currentBlock.append(fullTableHeader).append("\n");
}
currentBlock.append(tableRow).append("\n");
index++;
first = false;
}
// 如果当前块超过最大长度,进行分割
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 判断是否为表格分隔行
* 表格分隔行通常包含|和-字符,如:|------|------|
*
* @param line 要检查的行
* @return 如果是表格分隔行返回true,否则返回false
*/
private static boolean isTableSeparator(String line) {
return line.matches("^\\|?[ \\t]*:?[-]+:?[ \\t]*\\|([ \\t]*:?[-]+:?[ \\t]*\\|)*[ \\t]*$");
}
/**
* 处理Markdown代码块
* 代码块以```开始和结束,需要保持其完整性
*
* @param lines 所有文本行
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的行索引
* @return 处理完代码块后的下一行索引
*/
private static int processCodeBlock(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
// 检查是否需要分割当前块以容纳代码块开始标记
boolean needSplit = shouldSplitBlock(currentBlock, lines[index], maxlength);
if (needSplit) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(lines[index]).append("\n");
index++;
// 处理代码块的内容,直到找到结束标记
while (index < lines.length && (!lines[index].startsWith("```") || countBackticks(lines[index]) % 2 != 0)) {
String codeLine = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, codeLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(codeLine).append("\n");
index++;
}
// 处理代码块结束标记
if (index < lines.length) {
String endLine = lines[index];
if (shouldSplitBlock(currentBlock, endLine, maxlength)) {
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(endLine).append("\n");
index++;
}
// 如果当前块超过最大长度,进行分割
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 处理Markdown列表
* 支持有序列表(数字.)和无序列表(-)
*
* @param lines 所有文本行
* @param currentBlock 当前文本块
* @param currentTitle 当前标题
* @param result 结果列表
* @param maxlength 最大长度限制
* @param startIndex 开始处理的行索引
* @return 处理完列表后的下一行索引
*/
private static int processList(String[] lines, StringBuilder currentBlock, String currentTitle,
List<String> result, int maxlength, int startIndex) {
int index = startIndex;
boolean needSplit = false;
// 处理列表的所有项
while (index < lines.length && (lines[index].matches("^\\d+\\. ") || lines[index].startsWith("- "))) {
String listLine = lines[index];
// 检查是否需要分割
if (shouldSplitBlock(currentBlock, listLine, maxlength)) {
needSplit = true;
addCurrentBlockToResult(result, currentBlock);
currentBlock.append(currentTitle).append("\n");
}
currentBlock.append(listLine).append("\n");
index++;
}
// 如果没有需要分割且包含标题,删除标题以避免重复
if (!needSplit && currentBlock.length() > 0 && currentBlock.toString().contains(currentTitle + "\n")) {
currentBlock.delete(0, currentTitle.length() + 1);
}
// 如果当前块超过最大长度,进行分割
if (currentBlock.length() > maxlength) {
addCurrentBlockToResult(result, currentBlock);
}
return index;
}
/**
* 统计一行中反引号(`)的数量
* 用于判断代码块的开始和结束
*
* @param line 要统计的文本行
* @return 反引号的数量
*/
private static int countBackticks(String line) {
int count = 0;
for (char c : line.toCharArray()) {
if (c == '`') {
count++;
}
}
return count;
}
}
Kimi-K2模型生成的注释体现了典型的Trae系模型精炼风格。在类级别注释中,它用简洁的语言概括了核心功能(“将长Markdown文本按照指定最大长度分割成多个块,同时保持文档结构的完整性”)并列出三大主要特性。方法注释层面,对关键方法如splitMarkdown和processTable均准确描述了输入输出参数及核心逻辑,例如在表格处理方法中明确标注"表格需要特殊处理以保持其结构完整性"。
注释连贯性表现良好,从类概述到方法细节形成完整叙事链,特别是通过"主要功能"列表与具体方法实现形成呼应。准确性方面,所有注释均与实际代码逻辑高度匹配,如对isTableSeparator方法的正则表达式判断逻辑描述准确无误。
相较于其他Trae模型,Kimi-K2在保持精炼特质的同时,在复杂逻辑处(如表格处理流程)提供了更细致的步骤说明,这使其在保证简洁性的前提下增强了可读性。不过与Cursor系的Sonet模型相比,仍缺乏具体用法示例,如未展示分割后的文本块格式样例。整体而言,Kimi-K2的注释质量在Trae系列中属于上乘,既能满足开发理解需求,又避免了过度冗长的问题。
注释结果汇总表
| 模型名称 | 所属工具 | 注释风格 | 是否提供例子 | 理解准确度 |
|---|---|---|---|---|
| Sonet4.5 | Cursor 2.0 | 详细 | 是 | 高 |
| Composer | Cursor 2.0 | 详细 | 是 | 高 |
| Deepseek 3.1 Terminus | Trae 2.10 | 精炼 | 否 | 高 |
| Qwen3-coder | Trae 2.10 | 精炼 | 否 | 高 |
| GLM-4.6 | Trae 2.10 | 精炼 | 否 | 高 |
| Kimi-K2 | Trae 2.10 | 精炼 | 否 | 高 |
分析与比较
工具间注释风格对比
在本次评测中,Cursor 2.0和Trae 2.10工具下的模型在注释风格上呈现明显差异。Cursor生成的注释更详细,部分模型如Composer和Sonet4.5在方法中嵌入具体示例,例如Composer在processTable方法注释中直接展示表格结构示例(如|---|---|),并解释正则匹配规则,帮助新手理解复杂逻辑;Sonet4.5则通过编号列表结构化描述算法流程。这种风格适合初学者或处理复杂代码场景,能降低理解成本。相比之下,Trae工具下的模型(如Deepseek 3.1 Terminus、GLM-4.6和Qwen3-coder)注释更精炼,侧重核心功能,例如Deepseek的类注释仅用三行概括主要用途,方法注释直击参数和返回值,无冗余示例,适合快速代码浏览和审查。
这种差异可能源于工具算法和训练数据:Cursor的多Agent协作架构强调智能并行处理,其模型训练可能注重详细解释和实例化数据,以提升辅助深度;而Trae的SOLO模式专注于自动化全生命周期,模型训练更偏向效率优先,数据可能强化核心功能描述。尽管风格不同,但两类注释均准确匹配代码逻辑,达到开发标准。
各模型注释质量可视化
模型优缺点总结表
| 模型名称 | 优点 | 缺点 |
|---|---|---|
| Sonet4.5 | 注释详细,提供完整功能说明和使用场景,采用结构化描述提升可读性,包含正则表达式解析和格式示例 | 可能过于冗长,部分边界条件说明不够充分 |
| Composer | 注释深度超越基础功能描述,示例丰富度高,在核心方法中嵌入结构示例和正则模式示例,采用"示例驱动"注释风格 | 可能过于详细,未提供独立的使用示例代码段 |
| GLM-4.6 | 精炼风格,保留关键信息同时避免冗余,注释对开发者友好,平衡精炼与信息完整性 | 缺乏具体示例,注释相对简洁 |
| Qwen3-coder | 注释结构规整,清晰描述整体功能,语言流畅,结构清晰,精炼且聚焦核心逻辑 | 缺乏示例,与其他Trae模型一样未提供具体实例说明 |
| Kimi-K2 | 精炼风格,在复杂逻辑处提供细致步骤说明,保证简洁性的同时增强可读性,注释质量在Trae系列中属于上乘 | 缺乏具体用法示例,未展示分割后的文本块格式样例 |
| Deepseek 3.1 Terminus | 精炼准确,注释风格简洁,保证开发人员快速理解代码意图,避免过度描述带来的阅读负担 | 缺乏示例,未展示分割后的文本块格式样例 |
结论
评测总结与推荐
本次评测的核心发现是,所有参与评测的大模型在代码注释生成方面均能达到开发标准,注释内容准确反映了代码逻辑,理解到位。在工具层面,Cursor 2.0下的模型(如Sonet4.5和Composer)生成的注释更为详细,常嵌入具体示例和结构化说明,适合需要深入理解复杂逻辑的场景;而Trae 2.10下的模型(如Deepseek 3.1 Terminus、GLM-4.6等)注释风格精炼,聚焦核心功能与参数说明,适合效率优先的快速开发环境。因此,“代码好帮手”的选择取决于具体需求——追求详细注释和示例支持时可选Cursor,注重简洁高效则选Trae。总体来看,大模型在辅助编程中展现出巨大潜力,国产模型如GLM-4.6、Qwen3-coder等表现不俗,为开发者提供了可靠支持。
更多推荐
所有评论(0)