活力39173
在线时间13450 小时
阅读权限200
管理员
自由的灵魂
- 积分
- 106852
- 主题
- 5602
- 回帖
- 26633
- 注册时间
- 2003-4-10
- 最后登录
- 2026-8-14
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
1、问题缘起
用户反馈在使用 Markdown 转 UBB 工具时,代码块中的前导空格(缩进)全部丢失,导致代码格式化完全失效。例如以下 Python 代码:
- def test():
- if True:
- print("hello")
复制代码
转换后变成:
- def test():
- if True:
- print("hello")
复制代码
探讨过程中发现的问题:
| 序号 | 问题 | 状态 | | 1 | _ 下划线被作为斜体标志处理,导致代码中的变量名(如 _variable)被错误转换 | ✅ 已修复 | | 2 | 代码块在被 processNestedListsFixed 函数处理时,trim() 移除了行首空格 | ✅ 已修复 | | 3 | 代码块提取时机过晚,在标题、列表等处理之后才提取 | ✅ 已修复 | | 4 | 代码块占位符在列表处理中被当作列表项内容,缩进被破坏 | ✅ 已修复 |
2、解决方案
(1)简要技术分析
核心思路: 在函数最开始时将完整代码块替换为唯一占位符,待所有 Markdown 语法处理完成后再还原为 【code】 标签,使代码块内容在整个转换过程中完全隔离,不被任何正则或处理函数影响。
(2)修改文件列表
| 文件路径 | 修改类型 | | index.html(或 index.php)中的 JavaScript 代码段 | 修改 |
具体修改位置:
- markdownToUBB 函数:重写代码块提取与还原逻辑
- processNestedListsFixed 函数:删除代码块相关特殊处理
- isListItem 函数:移除代码块占位符跳过逻辑
- 基本转换规则:移除 _ 斜体支持
(3)关键作用代码段
① 重写后的 markdownToUBB 函数(核心改动)
- function markdownToUBB(markdown, baseUrl = '') {
- if (!markdown) return '';
- let ubb = markdown;
- // ===== 第1步:在最开始提取完整代码块 =====
- let codeBlockPlaceholders = [];
- let codeBlockIndex = 0;
- // 提取 ``` 代码块
- ubb = ubb.replace(/^[ \t]*```[\s\S]*?\n([\s\S]*?)\n[ \t]*```/gm, function(match, codeContent) {
- const placeholder = '###CODEBLOCK' + codeBlockIndex + '###';
- codeBlockIndex++;
- codeBlockPlaceholders.push(codeContent); // 只存内容,不加任何标签
- return placeholder;
- });
- // 提取 ~~~~ 代码块
- ubb = ubb.replace(/^[ \t]*~~~~[\s\S]*?\n([\s\S]*?)\n[ \t]*~~~~/gm, function(match, codeContent) {
- const placeholder = '###CODEBLOCK' + codeBlockIndex + '###';
- codeBlockIndex++;
- codeBlockPlaceholders.push(codeContent);
- return placeholder;
- });
- // ===== 第2步:处理所有 Markdown 语法 =====
- // 标题、水平线、加粗、斜体(已移除 _ 支持)、列表、链接、图片、引用、表格...
- // ===== 第3步:最后还原代码块 =====
- ubb = ubb.replace(/###CODEBLOCK(\d+)###/g, function(match, index) {
- const idx = parseInt(index);
- const codeContent = codeBlockPlaceholders[idx] || '';
- return '【code】' + codeContent + '【/code】';
- });
- return ubb;
- }
复制代码
② 移除 _ 斜体支持
- // 基本转换规则(仅保留 * 作为斜体,放弃 _)
- ubb = ubb
- .replace(/\*\*(.*?)\*\*/g, '[b]$1[/b]')
- .replace(/__(.*?)__/g, '[b]$1[/b]')
- .replace(/\*(.*?)\*/g, '[i]$1[/i]')
- // 已删除:.replace(/_(.*?)_/g, '[i]$1[/i]')
- .replace(/~~(.*?)~~/g, '[s]$1[/s]')
- .replace(/`(.*?)`/g, '[font=Courier New][color=#D63384]$1[/color][/font]');
复制代码
③ 简化 processNestedListsFixed 中的 isListItem 函数
- function isListItem(line) {
- const trimmed = line.trim();
- // 不再需要跳过代码块占位符
- if (/^#{1,6}\s/.test(trimmed)) return false;
- if (/^\[size=\d\]/.test(trimmed)) return false;
- return /^([-*+]|\d+\.)\s+/.test(trimmed);
- }
复制代码
④ 删除列表处理中的代码块特殊逻辑
- // 在 processNestedListsFixed 中删除以下代码块
- /*
- if (nextLine.trim().startsWith('###CODEBLOCK')) {
- itemLines.push(nextLine);
- j++;
- continue;
- }
- */
复制代码
3、最终实现效果
| 测试场景 | 修复前 | 修复后 | | Python 代码缩进 | 全部丢失 | ✅ 完整保留 | | 代码中的 _variable | 被转换为斜体 variable | ✅ 原样保留 _variable | | 代码中的 * 号 | 可能被转换为斜体 | ✅ 原样保留 | | 代码中的 # 号 | 可能被转换为标题 | ✅ 原样保留 | | 代码块在列表中的缩进 | 丢失 | ✅ 完整保留 | | 代码块在引用中的缩进 | 丢失 | ✅ 完整保留 |
测试用例:
输入 Markdown:
- - 列表项1
- - 列表项2
- ```python
- def test():
- if True:
- print("hello")
- ```
- - 列表项3
复制代码
修复前输出:
- [list]
- [*] 列表项1
- [*] 列表项2
- 【code】def test():
- if True:
- print("hello")【/code】
- [*] 列表项3
- [/list]
复制代码
修复后输出:
- [list]
- [*] 列表项1
- [*] 列表项2
- 【code】def test():
- if True:
- print("hello")【/code】
- [*] 列表项3
- [/list]
复制代码
4、重要技术沉淀
核心原则: 对于包含特殊字符且不应被解析的内容(如代码块),应在所有处理流程之前提取为占位符,在所有处理流程之后再还原。这样能保证内容100%无损,且不需要在多个处理函数中打补丁。
识别信号: 当某个功能需要你在多处代码中添加 if 判断来跳过特殊内容时,说明架构设计有问题,应该考虑将特殊内容提前隔离。
5、进一步优化的可能性
- 支持更多代码块格式:目前支持 和 ,可扩展支持 ~~~` 和缩进式代码块(行首4个空格)
- 代码块语言标识:可考虑在 【code】 标签中保留语言标识,如 [code=python],方便论坛语法高亮插件识别
- 行号显示:可增加选项,在代码块中自动添加行号
|
|