尽量从 LLM / 日志 / jsonl / Markdown 片段中提取合法 JSON。 参数 ---- text : str 输入原始文本 merge_dicts : bool, default False 提取到多个对象且全部是 dict 时,是否用 dict.update 合并返回 strip_double_braces : bool, default False 把 '{{' / '}}' 替换成 '{' / '}'(某些模板语言会加双层花括号) 返回 ----
(
text: str,
*,
merge_dicts: bool = False,
strip_double_braces: bool = False
)
| 39 | return Path(__file__).resolve().parent.parent |
| 40 | |
| 41 | def robust_parse_json( |
| 42 | text: str, |
| 43 | *, |
| 44 | merge_dicts: bool = False, |
| 45 | strip_double_braces: bool = False |
| 46 | ) -> Union[Dict[str, Any], List[Any]]: |
| 47 | """ |
| 48 | 尽量从 LLM / 日志 / jsonl / Markdown 片段中提取合法 JSON。 |
| 49 | |
| 50 | 参数 |
| 51 | ---- |
| 52 | text : str |
| 53 | 输入原始文本 |
| 54 | merge_dicts : bool, default False |
| 55 | 提取到多个对象且全部是 dict 时,是否用 dict.update 合并返回 |
| 56 | strip_double_braces : bool, default False |
| 57 | 把 '{{' / '}}' 替换成 '{' / '}'(某些模板语言会加双层花括号) |
| 58 | |
| 59 | 返回 |
| 60 | ---- |
| 61 | Dict / List / List[Dict | List] |
| 62 | """ |
| 63 | s = text.strip() |
| 64 | |
| 65 | # ---------- 预处理:剥去外层包裹 ---------- |
| 66 | s = _remove_markdown_fence(s) # ```json ... ``` |
| 67 | s = _remove_outer_triple_quotes(s) # ''' ... ''' / """ ... """ |
| 68 | s = _remove_leading_json_word(s) # 开头一个 json/JSON 标记 |
| 69 | |
| 70 | if strip_double_braces: |
| 71 | s = s.replace("{{", "{").replace("}}", "}") |
| 72 | |
| 73 | # ---------- 清理注释 & 尾逗号 ---------- |
| 74 | s = _strip_json_comments(s) |
| 75 | |
| 76 | # ---------- 新增:清理非法控制字符 ---------- |
| 77 | # 移除所有 JSON 规范不允许的 ASCII 控制字符。 |
| 78 | # 合法的 \n, \r, \t, 和 \f, \b, \" 都不会被移除,但这里只针对不可打印的控制码。 |
| 79 | s = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', s) |
| 80 | |
| 81 | # ---------- 新增:转义未转义的反斜杠(修复 LaTeX 公式等问题)---------- |
| 82 | # 这会将所有单个反斜杠转换为双反斜杠,但保留已经正确转义的序列 |
| 83 | # 先保护已经转义的序列(如 \\n, \\t, \\", \\\\) |
| 84 | s = s.replace('\\\\', '\x00DOUBLE_BACKSLASH\x00') # 临时标记 |
| 85 | s = s.replace('\\n', '\x00NEWLINE\x00') |
| 86 | s = s.replace('\\r', '\x00RETURN\x00') |
| 87 | s = s.replace('\\t', '\x00TAB\x00') |
| 88 | s = s.replace('\\"', '\x00QUOTE\x00') |
| 89 | s = s.replace('\\/', '\x00SLASH\x00') |
| 90 | s = s.replace('\\b', '\x00BACKSPACE\x00') |
| 91 | s = s.replace('\\f', '\x00FORMFEED\x00') |
| 92 | |
| 93 | # 现在转义所有剩余的单个反斜杠 |
| 94 | s = s.replace('\\', '\\\\') |
| 95 | |
| 96 | # 恢复之前保护的序列 |
| 97 | s = s.replace('\x00DOUBLE_BACKSLASH\x00', '\\\\') |
| 98 | s = s.replace('\x00NEWLINE\x00', '\\n') |
no test coverage detected