Files
doc_processer/docs/DIFFERENTIAL_PATTERN_BUG_FIX.md
2026-02-05 13:18:55 +08:00

5.6 KiB
Raw Blame History

LaTeX 命令被拆分的 Bug 修复

问题描述

前端使用 Markdown 渲染时,发现 LaTeX 命令被错误拆分:

  • \vdots\vd ots
  • \lambda_{1}\lambd a_{1}

根本原因

位置: app/services/ocr_service.py 第 51-52 行

Bug 代码:

_DIFFERENTIAL_LOWER_PATTERN = re.compile(r"(?<!\\)d([a-z])")

问题分析:

这个正则表达式的意图是匹配微分符号(如 dx, dy),但它的匹配规则是:

  • (?<!\\) - d 前面不是反斜杠
  • d([a-z]) - d 后面跟一个小写字母

Bug 示例:

LaTeX 命令 内部匹配到 替换结果 问题
\vdots do (d+o) \vd ots 命令被破坏
\lambda da (d+a) \lambd a 命令被破坏
\delta de (d+e) \d elta 命令被破坏
\cdots do (d+o) \cd ots 命令被破坏
\ldots do (d+o) \ld ots 命令被破坏

为什么会匹配到命令内部:

\vdots 中:

  • v 不是反斜杠 ✓
  • d 后面是 o (小写字母) ✓
  • 正则表达式匹配成功 → 替换为 d o → 结果:\vd ots

修复方案

新代码:

# 确保 d 前面不是反斜杠,也不是字母(避免匹配命令内部)
_DIFFERENTIAL_UPPER_PATTERN = re.compile(r"(?<!\\)(?<![a-zA-Z])d([A-Z])")
_DIFFERENTIAL_LOWER_PATTERN = re.compile(r"(?<!\\)(?<![a-zA-Z])d([a-z])")

修复逻辑:

新增了 (?<![a-zA-Z]) 负向后查找,确保:

  • d 前面不是反斜杠 \
  • d 前面也不是任何字母 ← 新增的保护

效果对比:

LaTeX 旧模式Bug 新模式Fixed 说明
\vdots \vd ots \vdots v 是字母,不匹配
\lambda \lambd a \lambda b 是字母,不匹配
\delta \d elta \delta l 是字母,不匹配
dx d x d x 前面无字母,正常匹配
\int dx \int d x \int d x 空格后的 d,正常匹配
(dx) (d x) (d x) ( 不是字母,正常匹配

测试验证

测试 1: LaTeX 命令不应该被修改

# 这些应该保持不变
test_commands = [
    r"\vdots",
    r"\lambda_{1}",
    r"\delta",
    r"\cdots",
    r"\ldots",
]

# 新模式:全部通过 ✅
# 旧模式:全部失败 ❌

测试 2: 微分符号应该被正确处理

# 这些应该被转换
test_differentials = [
    r"dx",           # → "d x"
    r"dy",           # → "d y"
    r"\int dx",      # → "\int d x"
    r"(dx)",         # → "(d x)"
]

# 新模式:全部通过 ✅
# 旧模式:全部通过 ✅

测试 3: 用户报告的具体问题

# 用户报告的问题
assert process(r"\vdots") == r"\vdots"         # ✅ 修复
assert process(r"\lambda_{1}") == r"\lambda_{1}"  # ✅ 修复

影响范围

受益的 LaTeX 命令

所有包含字母 d 的 LaTeX 命令现在都能正确处理:

希腊字母:

  • \delta (δ)
  • \Delta (Δ)

省略号:

  • \vdots (⋮)
  • \cdots (⋯)
  • \ldots (…)
  • \ddots (⋱)
  • \iddots (⋰)

其他命令:

  • \lambda (λ)
  • 任何自定义命令(如 \myd, \customd 等)

不受影响的功能

微分符号的识别和规范化仍然正常工作:

  • dxd x
  • dyd y
  • dV\mathrm{d} V
  • \int f(x) dx\int f(x) d x

部署步骤

  1. 修改已完成: app/services/ocr_service.py 已更新

  2. 重启服务:

    # 重启 FastAPI 服务使修改生效
    
  3. 验证修复:

    # 测试 vdots
    curl -X POST "http://localhost:8000/api/v1/image/ocr" \
      -H "Content-Type: application/json" \
      -d '{"image_base64": "...", "model_name": "paddle"}'
    
    # 检查返回的 markdown 字段,确认 \vdots 和 \lambda 没有被拆分
    
  4. 前端测试: 在前端 React 应用中测试完整的渲染流程

技术细节

正则表达式解释

旧模式:

r"(?<!\\)d([a-z])"
  • (?<!\\) - 负向后查找:前面不是 \
  • d - 匹配字母 d
  • ([a-z]) - 捕获组:匹配一个小写字母

新模式:

r"(?<!\\)(?<![a-zA-Z])d([a-z])"
  • (?<!\\) - 负向后查找:前面不是 \
  • (?<![a-zA-Z]) - 负向后查找:前面不是字母 ← 关键修复
  • d - 匹配字母 d
  • ([a-z]) - 捕获组:匹配一个小写字母

为什么添加 (?<![a-zA-Z])

LaTeX 命令的特点:

  • 都以反斜杠开头:\command
  • 命令名由字母组成:\alpha, \beta, \lambda, \vdots

所以命令内部的 d 前面总是有另一个字母(如 \vdots 中的 v)。

通过添加 (?<![a-zA-Z]),我们确保:

  • LaTeX 命令内部的 d 不会被匹配(因为前面是字母)
  • 独立的微分符号 dx 可以被匹配(因为前面不是字母)

相关文件

  • 修复文件: app/services/ocr_service.py (行 50-54)
  • 测试文件: test_differential_bug_fix.py
  • 快速测试: test_quick_fix.py

总结

方面 状态
问题根源 已定位(微分规范化正则表达式)
修复方案 已实施(添加字母负向后查找)
LaTeX 命令保护 \vdots, \lambda 等不再被拆分
微分符号处理 dx, dy 仍正常工作
代码质量 无 linter 错误

修复状态: 完成,等待重启服务验证

优先级: 🔴 (影响所有包含字母 d 的 LaTeX 命令)