找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 49|回复: 1

[维护日志] [2026-07-26] [修复] [列表处理与空行清理] - 修复嵌套列表闭合错位、清除空行失效及列表后多余空行

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

9336

威望

6965

金钱

1万

贡献

管理员

自由的灵魂

积分
106908
主题
5610
回帖
26637
注册时间
2003-4-10
最后登录
2026-8-17
发表于 2026-7-27 01:39:51 | 显示全部楼层 |阅读模式

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

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

×
1、问题缘起

在测试 Markdown 转 UBB 功能时,连续发现三个关联问题:

序号
问题描述现象
嵌套列表以空行接正文结束时,父级  出现在正文之后"总结句"被错误包裹进列表内,Discuz 中排版错乱
点击"清除空行"按钮无任何效果功能完全失效
关闭标签后若存在多个空行,发帖到 Discuz 后列表与正文之间出现两个空行排版间距过大


其中问题②在排查过程中发现:原代码的设计意图本是"保留段落间单空行",但步骤2的正则写崩导致整个功能失效,昨日一度误改为"彻底清空所有空行"。经用户提醒后,现已回归原设计意图。




2、解决方案

(1)简要技术分析

一句话概括: 在子列表收集阶段引入"空行后内容预判"机制,让空行成为列表边界信号;同时用 \n{3,} → \n\n 统一压缩多空行为单空行,并在  标签后同步做空行收敛,确保工具输出与 Discuz 渲染一致。

(2)修改文件列表

  • index.php(Markdown转UBB工具主文件)

(3)关键作用代码段全文

修改点①:嵌套列表空行边界检测(processNestedListsFixed 函数)

将子列表循环中的空行跳过逻辑:
  1.                     if (subLine.trim() === '') { k++; continue; }
复制代码


替换为空行后内容检测逻辑:
  1.                     if (subLine.trim() === '') {
  2.                         let afterEmptyIdx = k + 1;
  3.                         while (afterEmptyIdx < lines.length && lines[afterEmptyIdx].trim() === '') {
  4.                             afterEmptyIdx++;
  5.                         }
  6.                         if (afterEmptyIdx < lines.length) {
  7.                             const afterEmptyLine = lines[afterEmptyIdx];
  8.                             if (!isListItem(afterEmptyLine) || getIndentLevel(afterEmptyLine) < nextIndent) {
  9.                                 break;
  10.                             }
  11.                         }
  12.                         k++;
  13.                         continue;
  14.                     }
复制代码


修改点②:清除空行功能修复(removeEmptyLinesFn 函数)

原代码(步骤2正则 color=#D63384{2,} 永远匹配不到,导致失效):
  1.         function removeEmptyLinesFn() {
  2.     if (!ubbResult.value.trim()) return;
  3.     let compressed = ubbResult.value.replace(/\n{3,}/g, '\n\n');
  4.     compressed = compressed.replace(/(\n\n){2,}/g, '\n\n');
  5.     ubbResult.value = compressed;
  6.     updateCharCount();
  7.     showNotification('已清除多余空行(保留段落结构)', 'info');
  8. }
复制代码


修正后(回归原设计:仅压缩3个及以上换行为2个换行,保留段落间单空行):
  1.         function removeEmptyLinesFn() {
  2.     if (!ubbResult.value.trim()) return;
  3.     // 将连续3个及以上换行(即2个及以上空行)压缩为2个换行,保留段落间单空行
  4.     ubbResult.value = ubbResult.value.replace(/\n{3,}/g, '\n\n');
  5.     updateCharCount();
  6.     showNotification('已清除多余空行(保留段落间单空行)', 'info');
  7. }
复制代码


修改点③:列表关闭后空行压缩(markdownToUBB 函数第3步)

在原有清理规则后新增:
  1.     // 将 [/list] 后的多个空行压缩为单个换行,避免列表与正文之间出现多余空行
  2.     ubb = ubb.replace(/(\[\/list(?:=1)?\])\n{2,}/g, '$1\n');
复制代码





3、最终实现效果

场景修复前输出修复后输出
状态
嵌套列表+空行+正文\n\n总结句。\n\n\n总结句。
✅ 正常
点击"清除空行"(3个空行)无反应压缩为1个空行
✅ 正常
点击"清除空行"(原本只有1个空行)无反应保持不变
✅ 正常
列表后多空行\n\n\n正文\n正文
✅ 正常
列表间正常换行\n


\n


✅ 不受影响





4、重要技术沉淀

  • 空行语义陷阱: 在列表解析中,空行不应被简单 continue 跳过,而应作为"列表是否继续"的判断信号。子列表收集循环必须对空行后的内容做前瞻判断。
  • 正则叠加陷阱(本次核心踩坑): 原代码步骤1 replace(/\n{3,}/g, '\n\n') 逻辑正确,但步骤2 replace(/(\n\n){2,}/g, '\n\n') 要求至少4个连续换行才能匹配,而步骤1已经把3个以上压缩成2个了,导致步骤2永远匹配不到——一个画蛇添足的步骤2毁掉了整个功能。修正方案是只保留步骤1,删掉步骤2。
  • 设计意图的保护: 原设计本就是"保留段落间单空行",但在修复过程中一度被误改为"彻底清空所有空行"。后续修复时应先理解原有代码的设计意图,再判断是逻辑错误还是实现错误。
  • Discuz 适配原则:【/list】 后接 \n\n 会被 Discuz 编辑器渲染为两个空行,接 \n 恰好一个空行。工具侧应在输出阶段就把 \n{2,} 压成 \n,避免依赖论坛编辑器二次处理。
不懂就搜!点此搜点拨论坛。如果本坛没有,请尝试点此问AI,或跟帖提问。
发帖前注意看置顶帖
不定期借助AI对点拨论坛陈年老帖进行挖坟回复,打扰勿怪!
自己麻烦些,让帮你的人轻松些
  • 打卡等级:本地老炮

9336

威望

6965

金钱

1万

贡献

管理员

自由的灵魂

积分
106908
主题
5610
回帖
26637
注册时间
2003-4-10
最后登录
2026-8-17
 楼主| 发表于 2026-7-27 11:05:19 | 显示全部楼层
测试Markdown:

  1. ### 📝 标题

  2. *   **列表项A**:
  3.     *   子列表项A
  4.     *   子列表项B

  5. *   **列表项B**:正文

  6. *   **列表项C**:引文:
  7.     1.  子列表项C。
  8.     2.  子列表项C。

  9. 总结句。
复制代码
不懂就搜!点此搜点拨论坛。如果本坛没有,请尝试点此问AI,或跟帖提问。
发帖前注意看置顶帖
不定期借助AI对点拨论坛陈年老帖进行挖坟回复,打扰勿怪!
发现掉链,请直接回帖报告。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2026-8-17 09:43 , Processed in 0.045118 second(s), 8 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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