三个数算的是三种账
粘一段 HTML 跑完,统计条只给三个数:移除标签 19、原始字符 227、结果字符 79。可 19 和 148 不是同一种量。把这页模板(150 行 / 6391 字节)里唯一的处理函数逐字抽出来在 Node 里驱动,跑同一串 13 行 / 227 字符的样例:19 是 6 处 .match() 命中数之和(第 92 行起),227 与 79 是第 146、147 行的两个 .length,相减的 148 才是真正消失的字符数——每报 1 个标签,就有 7.79 个字符走掉。
模式(去除所有 / 去除指定)× 保留标签内内容 × 去注释 × 压空格,4 个开关展开成 16 组。在 HTML标签去除 上把这 16 格逐格拨一遍,同一串 227 字符的结果全在下表。
16 组矩阵:只有 1 个开关动计数
| 组 | 模式 | 内容 | 注释 | 空格 | 移除标签 | 实删字符 |
|---|---|---|---|---|---|---|
| 1 | all | 开 | 开 | 开 | 19 | 148 |
| 2 | all | 开 | 开 | 关 | 19 | 140 |
| 3 | all | 开 | 关 | 开 | 19 | 136 |
| 4 | all | 开 | 关 | 关 | 19 | 129 |
| 5 | all | 关 | 开 | 开 | 14 | 181 |
| 6 | all | 关 | 开 | 关 | 14 | 172 |
| 7 | all | 关 | 关 | 开 | 14 | 169 |
| 8 | all | 关 | 关 | 关 | 14 | 161 |
| 9 | 指定 | 开 | 开 | 开 | 10 | 86 |
| 10 | 指定 | 开 | 开 | 关 | 10 | 80 |
| 11 | 指定 | 开 | 关 | 开 | 10 | 74 |
| 12 | 指定 | 开 | 关 | 关 | 10 | 69 |
| 13 | 指定 | 关 | 开 | 开 | 5 | 133 |
| 14 | 指定 | 关 | 开 | 关 | 5 | 126 |
| 15 | 指定 | 关 | 关 | 开 | 5 | 121 |
| 16 | 指定 | 关 | 关 | 关 | 5 | 115 |
第 9 到 16 组填的是同一串 4 个标签名。四个开关里只有保留内容会动计数:移除标签在四个区段恒为 19、14、10、5,注释与空格一个都不影响它,结果字符只随这两个开关变。保留内容一拨,报数从 19 掉到 14、实删反而从 148 涨到 181。
图 1:四个区段各取注释与空格都开的那一格。
保留内容一关,被删的标签不上数
all 模式关掉这一档会换一条路径:第 96 行那 6 个 blockTags 先被第 98 行的整块正则删掉,第 102 行才开始计数,所以块的开闭标签一个都不进「移除标签」。样例上 19 掉到 14,差的 5 个正是 <style>、</style>、<script>、</script> 和字符串字面量里的 <div>。
54 个字符的一串:<style>.a{}</style><script>var a="<div>";</script>text。保留内容开着是移除 5、输出 17 字符;关掉只剩 4 字符的 text,移除标签却写 0。
指定标签做的是前缀匹配
标签名填进去后,第 115 行拼出的正则 '<'+tag+'[^>]*>' 前面没有边界。填 p,作用在 40 个字符的 <p>段落</p><pre> 代码</pre><param name="x"> 上:移除标签 4、输出 12 字符,<pre> 与 <param name="x"> 一起被删,closeRe 却要求 </p\s*>,闭标签留成残渣——删掉的 28 个字符只报了 4。填 i,69 个字符删到 10,img、iframe、input 三个开标签全没。
分隔符少一种,整串一字未改
字段标签写的是逗号分隔,清单两处示范却是顿号。第 109 行 split(/[,,\s]+/) 只认半角逗号、全角逗号和空白,顿号不在表里:照文案输入 script、style 只切出 1 个 token、净化成 scriptstyle,移除 0,84 个字符一字未改;同一串写成 script,style,div 就是移除 6、删掉 43 个。空值更安静:28 字符的一串移除 0、输出 16 字符,而同一串在 all 模式是移除 2、输出 5 字符——移除 0 不等于输出等于输入。
「所有」这个词撑不住
通用正则要求 < 后紧跟 ASCII 字母且必须有闭合的 >,默认组合有 7 类标记原样留下:<!DOCTYPE html> 的 15 个字符、<?xml version="1.0"?> 的 21、<3.5 的 4、<> 的 2、</> 的 3、未闭合 <div 的 4、< b>x</ b> 的 10。实体形态也不还原:<div> 的 11 个字符 0 匹配、一路留到输出, 与 U+00A0 同样不在处理范围;比较运算符也会被当成标签,<b && c> 这 8 个字符就是被吞掉的那个。
注释与空格这两档
注释是第 85 行的非贪婪匹配,遇到第一个结束符就收:未闭合的 17 字符原样保留,嵌套的只吃掉 19、留 6 个字符残渣。
空格是第 136 行里的 3 个 .replace(),压成 1 个空格而不是删除:中文段 9 个字符变 7;全角空格 U+3000 的 9 变 8,只删行首那 1 个;U+00A0 的 4 个不变、U+200B 的 3 个不变;单个换行不合并,3 连换行才从 5 变 3;CRLF 从 6 变 4。代码缩进最受伤:<pre> 段剥掉标签是 25 字符,开了压缩剩 19,首行缩进被直接删光。
一整页网页跑下来
换一页 19 行 / 569 字符的真实结构:默认组合报 32 个标签、输出 277 字符,第一行仍是 <!DOCTYPE html>,其中汉字只有 52 个、代码符号 53 个。只关保留内容,报数变 26、输出 88 字符,两版差的 189 个字符正是 CSS / JS / JSON-LD 源码的体量。
没有批量入口,也没有第二遍的惊喜
「批量」在这页不存在:第 70 行只读 1 个输入框的值、第 44 行只有 1 个输出区,0 处文件入口、0 处 FileReader、0 处遍历循环,跑第二段只能手工全选替换;6 个调用点无节流,5000 字符每敲一个字都重跑 12 次 .replace()。把输出灌回去跑第二遍,11 组里 10 组逐字节不变,只有 <<b>hi> 继续被改:第一遍输出 4 字符的 <hi>,第二遍输出 0 字符,而第二遍的移除标签普遍显示 0——它是本次快照、不是进度。
22 条文案对照
把 config/tools.php 第 1144–1152 行的 22 条文案逐条对着实测判一遍:[一致] 7 条、[冲突] 15 条,冲突集中在「提取纯文本」「仅移除指定标签」「可选去除连续空格和换行」这三句。站内那篇讲去除 HTML 标签的旧文是经验向叙述,这一篇不重复它,只把开关矩阵与计数补齐。
常见问题
Q:报 19 个标签,就是删掉 19 个标签吗?
不是。同一串 227 字符,保留内容开着报 19、关掉报 14,实删字符反而从 148 涨到 181:整块删除先跑、计数后跑,比值从 7.79 跳到 12.93。
Q:只填 p,为什么连 <pre> 一起没了?
第 115 行的正则没有前缀边界,p 会命中 pre 与 param;闭标签那边又要求一字不差,于是开标签被删、闭标签留成残渣。
Q:结果里还留着实体形态怎么办?
这页 0 处实体解码、0 处 DOM 解析,全是字符串替换:< 这种形态会一路留到输出。