
本文详解在 Jira ScriptRunner 环境下,如何将含 \r\n 换行符的 Markdown 表格字符串规范化为单行可处理格式,并结合 splitEachLine() 与结构化映射生成标准 JSON,避免正则因换行中断导致匹配失败。
本文详解在 jira scriptrunner 环境下,如何将含 `\r\n` 换行符的 markdown 表格字符串规范化为单行可处理格式,并结合 `spliteachline()` 与结构化映射生成标准 json,避免正则因换行中断导致匹配失败。
在 Jira Server 的 ScriptRunner(基于 Groovy/Java)中处理从 issue.getDescription() 获取的 Markdown 表格时,一个常见陷阱是:原始字符串虽在 REST API 响应中显示为含 \r\n 的多行文本(如 "||...|\r\n|*Task 1*|...\r\n"),但在 Groovy 字符串字面量或日志输出中,这些换行符已被 JVM 解析为实际换行——这会导致依赖单行匹配的正则表达式(如 ^.*$ 或跨列捕获)失效或漏匹配。
关键认知:无需“强制转为单行字符串”来迁就正则
与其费力将 \r\n 替换为空格或 \s 并承担格式错乱风险(例如表格单元格内本就有空格),不如采用更健壮、语义清晰的方案:直接按行分割 + 列对齐解析。Groovy 提供的 String.splitEachLine(pattern, closure) 正是为此场景优化的原生方法——它自动按行切分并逐行应用正则提取,天然兼容 CRLF/LF 换行,且不破坏原始字段内容。
以下为生产就绪的实现方案(适配您的 Jira ScriptRunner 环境):
import groovy.json.JsonOutput
// ✅ 安全获取描述内容(无需手动处理 \r\n)
def description = issue.getDescription() ?: ""
// ✅ 使用 splitEachLine 按 Markdown 表格行分割(兼容 \r\n 和 \n)
List<Map> actionItems = []
description.splitEachLine(/\r?\n/) { line ->
// 跳过空行和表头分隔线(如 ||...|| 或 |---|)
if (!line.trim() || line.trim().startsWith('|-')) return
// 使用正则精准提取各列(适配 *Task X* 格式及空格填充)
def matcher = line =~ /\|\*?([^|]*)\*?\|[^|]*\|([^|]*)\|[^|]*\|[^|]*\|([^|]*)\|/
if (matcher.find()) {
def title = matcher.group(1)?.trim() ?: ""
def dueDate = matcher.group(2)?.trim() ?: ""
def remarks = matcher.group(3)?.trim() ?: ""
// 构建标准化字段(注意:JSON Key 遵循您指定的大写+空格格式)
actionItems << [
"TITLE" : title,
"DUE DATE" : dueDate,
"DONE ON" : "", // 原数据中该列为空,按需补充逻辑
"NOTE" : remarks
]
}
}
// ✅ 过滤掉表头行(第一行含列名,非任务数据)
if (actionItems) {
actionItems = actionItems.drop(1)
}
// ✅ 生成符合要求的 JSON 结构
def result = [ACTION: actionItems]
log.info("Generated JSON: ${JsonOutput.toJson(result)}")
return JsonOutput.prettyPrint(JsonOutput.toJson(result))注意事项与最佳实践:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- ✅ 换行符兼容性:splitEachLine(/\r?\n/) 显式处理 Windows (\r\n) 和 Unix (\n) 换行,比 split('\n') 更可靠;ScriptRunner 运行时环境通常已正确解析 \r\n 为换行符,无需额外 replaceAll。
- ✅ 正则鲁棒性:使用 matcher.group(n) 显式捕获而非依赖 split('|')(易被单元格内竖线干扰),并用 ?.trim() 防空指针。
- ⚠️ 表头识别:Markdown 表格首行为列名(|| Due Date ||...),第二行为分隔线(|---|---|),需跳过;上述代码通过 drop(1) 简洁跳过首行,若需更精确可增加 line.contains('||') && !line.contains('|-') 判断。
- ? 空值安全:?: "" 确保空单元格生成空字符串而非 null,避免 JSON 序列化异常。
- ? 字段映射一致性:严格遵循您示例中的 JSON Key 名称(如 "DUE DATE" 而非 "dueDate"),确保下游系统无缝消费。
总结:在 Groovy/Java 生态中处理多行结构化文本,优先选择语义化解析(splitEachLine + 正则捕获)而非“扁平化为单行”。这不仅规避了换行符转义的复杂性,更提升了代码可读性、可维护性与容错能力——尤其在 Jira ScriptRunner 这类对稳定性要求极高的运维脚本场景中,是更专业、更可持续的选择。
立即学习“Java免费学习笔记(深入)”;

















