优化 json 格式处理

This commit is contained in:
zk
2026-04-29 18:23:28 +08:00
parent ad8fff3d62
commit d284673a36
5 changed files with 70 additions and 37 deletions
@@ -0,0 +1,58 @@
package org.jiayunet.ai;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* AI 响应文本清洗工具
* <p>从 AI 返回的原始文本中提取干净的 JSON 字符串,处理 markdown 代码块、前后说明文字、不可见控制字符等</p>
*
* @author zk
*/
public final class AiResponseCleanTool {
private AiResponseCleanTool() {
}
/** 匹配 markdown 代码块:```可选语言标识\n 内容 \n```DOTALL 让 . 匹配换行 */
private static final Pattern CODE_BLOCK_PATTERN = Pattern.compile("```\\w*\\s*\\n?(.*?)\\n?\\s*```", Pattern.DOTALL);
/** 匹配不可见控制字符(保留 \t \n \r) */
private static final Pattern CONTROL_CHAR_PATTERN = Pattern.compile("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]");
/**
* 清理 AI 返回的文本,提取其中的 JSON
* <p>1. null/空白返回空串 2. 优先从 markdown 代码块提取 3. 无代码块则定位首个 JSON 起始符 4. 清除控制字符</p>
*/
public static String clean(String response) {
if (response == null || response.isBlank()) {
return "";
}
String result = response.trim();
// 尝试从 markdown 代码块中提取
Matcher matcher = CODE_BLOCK_PATTERN.matcher(result);
if (matcher.find()) {
result = matcher.group(1).trim();
} else {
// 没有代码块时,尝试提取第一个 JSON 对象 {} 或数组 []
int jsonStart = findJsonStart(result);
if (jsonStart > 0) {
result = result.substring(jsonStart).trim();
}
}
// 清除控制字符
result = CONTROL_CHAR_PATTERN.matcher(result).replaceAll("");
return result;
}
/** 查找第一个 '{' 或 '[' 的位置,未找到返回 -1 */
private static int findJsonStart(String text) {
int objStart = text.indexOf('{');
int arrStart = text.indexOf('[');
if (objStart < 0) return arrStart;
if (arrStart < 0) return objStart;
return Math.min(objStart, arrStart);
}
}