找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 32|回复: 0

[维护日志] [2026-07-11] [修复] [Markdown代码块缩进丢失] - 修复代码块转换时前导空格被清除的问题

[复制链接]
  • 打卡等级:本地老炮

9336

威望

6912

金钱

1万

贡献

管理员

自由的灵魂

积分
106852
主题
5602
回帖
26633
注册时间
2003-4-10
最后登录
2026-8-14
发表于 2026-7-11 22:24:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1、问题缘起

用户反馈在使用 Markdown 转 UBB 工具时,代码块中的前导空格(缩进)全部丢失,导致代码格式化完全失效。例如以下 Python 代码:

  1. def test():
  2.     if True:
  3.         print("hello")
复制代码


转换后变成:

  1. def test():
  2. if True:
  3. print("hello")
复制代码


探讨过程中发现的问题:

序号问题状态
1_ 下划线被作为斜体标志处理,导致代码中的变量名(如 _variable)被错误转换✅ 已修复
2代码块在被 processNestedListsFixed 函数处理时,trim() 移除了行首空格✅ 已修复
3代码块提取时机过晚,在标题、列表等处理之后才提取✅ 已修复
4代码块占位符在列表处理中被当作列表项内容,缩进被破坏✅ 已修复





2、解决方案

(1)简要技术分析

核心思路: 在函数最开始时将完整代码块替换为唯一占位符,待所有 Markdown 语法处理完成后再还原为 【code】 标签,使代码块内容在整个转换过程中完全隔离,不被任何正则或处理函数影响。

(2)修改文件列表

文件路径修改类型
index.html(或 index.php)中的 JavaScript 代码段修改


具体修改位置:
  • markdownToUBB 函数:重写代码块提取与还原逻辑
  • processNestedListsFixed 函数:删除代码块相关特殊处理
  • isListItem 函数:移除代码块占位符跳过逻辑
  • 基本转换规则:移除 _ 斜体支持

(3)关键作用代码段

① 重写后的 markdownToUBB 函数(核心改动)

  1. function markdownToUBB(markdown, baseUrl = '') {
  2.     if (!markdown) return '';

  3.     let ubb = markdown;

  4.     // ===== 第1步:在最开始提取完整代码块 =====
  5.     let codeBlockPlaceholders = [];
  6.     let codeBlockIndex = 0;

  7.     // 提取 ``` 代码块
  8.     ubb = ubb.replace(/^[ \t]*```[\s\S]*?\n([\s\S]*?)\n[ \t]*```/gm, function(match, codeContent) {
  9.         const placeholder = '###CODEBLOCK' + codeBlockIndex + '###';
  10.         codeBlockIndex++;
  11.         codeBlockPlaceholders.push(codeContent);  // 只存内容,不加任何标签
  12.         return placeholder;
  13.     });

  14.     // 提取 ~~~~ 代码块
  15.     ubb = ubb.replace(/^[ \t]*~~~~[\s\S]*?\n([\s\S]*?)\n[ \t]*~~~~/gm, function(match, codeContent) {
  16.         const placeholder = '###CODEBLOCK' + codeBlockIndex + '###';
  17.         codeBlockIndex++;
  18.         codeBlockPlaceholders.push(codeContent);
  19.         return placeholder;
  20.     });

  21.     // ===== 第2步:处理所有 Markdown 语法 =====
  22.     // 标题、水平线、加粗、斜体(已移除 _ 支持)、列表、链接、图片、引用、表格...

  23.     // ===== 第3步:最后还原代码块 =====
  24.     ubb = ubb.replace(/###CODEBLOCK(\d+)###/g, function(match, index) {
  25.         const idx = parseInt(index);
  26.         const codeContent = codeBlockPlaceholders[idx] || '';
  27.         return '【code】' + codeContent + '【/code】';
  28.     });

  29.     return ubb;
  30. }
复制代码


② 移除 _ 斜体支持

  1. // 基本转换规则(仅保留 * 作为斜体,放弃 _)
  2. ubb = ubb
  3.     .replace(/\*\*(.*?)\*\*/g, '[b]$1[/b]')
  4.     .replace(/__(.*?)__/g, '[b]$1[/b]')
  5.     .replace(/\*(.*?)\*/g, '[i]$1[/i]')
  6.     // 已删除:.replace(/_(.*?)_/g, '[i]$1[/i]')
  7.     .replace(/~~(.*?)~~/g, '[s]$1[/s]')
  8.     .replace(/`(.*?)`/g, '[font=Courier New][color=#D63384]$1[/color][/font]');
复制代码


③ 简化 processNestedListsFixed 中的 isListItem 函数

  1. function isListItem(line) {
  2.     const trimmed = line.trim();
  3.     // 不再需要跳过代码块占位符
  4.     if (/^#{1,6}\s/.test(trimmed)) return false;
  5.     if (/^\[size=\d\]/.test(trimmed)) return false;
  6.     return /^([-*+]|\d+\.)\s+/.test(trimmed);
  7. }
复制代码


④ 删除列表处理中的代码块特殊逻辑

  1. // 在 processNestedListsFixed 中删除以下代码块
  2. /*
  3. if (nextLine.trim().startsWith('###CODEBLOCK')) {
  4.     itemLines.push(nextLine);
  5.     j++;
  6.     continue;
  7. }
  8. */
复制代码





3、最终实现效果

测试场景修复前修复后
Python 代码缩进全部丢失✅ 完整保留
代码中的 _variable被转换为斜体 variable✅ 原样保留 _variable
代码中的 *可能被转换为斜体✅ 原样保留
代码中的 #可能被转换为标题✅ 原样保留
代码块在列表中的缩进丢失✅ 完整保留
代码块在引用中的缩进丢失✅ 完整保留


测试用例:

输入 Markdown:
  1. - 列表项1
  2. - 列表项2
  3.    ```python
  4.    def test():
  5.        if True:
  6.            print("hello")
  7.    ```
  8. - 列表项3
复制代码


修复前输出:
  1. [list]
  2. [*] 列表项1
  3. [*] 列表项2
  4. 【code】def test():
  5. if True:
  6. print("hello")【/code】
  7. [*] 列表项3
  8. [/list]
复制代码


修复后输出:
  1. [list]
  2. [*] 列表项1
  3. [*] 列表项2
  4. 【code】def test():
  5.     if True:
  6.         print("hello")【/code】
  7. [*] 列表项3
  8. [/list]
复制代码





4、重要技术沉淀

核心原则: 对于包含特殊字符且不应被解析的内容(如代码块),应在所有处理流程之前提取为占位符,在所有处理流程之后再还原。这样能保证内容100%无损,且不需要在多个处理函数中打补丁。

识别信号: 当某个功能需要你在多处代码中添加 if 判断来跳过特殊内容时,说明架构设计有问题,应该考虑将特殊内容提前隔离。




5、进一步优化的可能性

  • 支持更多代码块格式:目前支持 ,可扩展支持 ~~~` 和缩进式代码块(行首4个空格)
  • 代码块语言标识:可考虑在 【code】 标签中保留语言标识,如 [code=python],方便论坛语法高亮插件识别
  • 行号显示:可增加选项,在代码块中自动添加行号
不懂就搜!点此搜点拨论坛。如果本坛没有,请尝试点此问AI,或跟帖提问。
发帖前注意看置顶帖
不定期借助AI对点拨论坛陈年老帖进行挖坟回复,打扰勿怪!
在帮助别人的过程中丰富自己
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|点拨论坛 |网站地图|网站地图

GMT+8, 2026-8-14 21:28 , Processed in 0.036486 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表