杂记 › 生活随笔 › 四个开关默认开着哪三个:文本集合运算的折叠口径、代表元与去重短路实测

四个开关默认开着哪三个:文本集合运算的折叠口径、代表元与去重短路实测

文本集合运算页四个开关默认开着去空格、忽略空行、结果去重三个,只有区分大小写不勾。实测五步判定顺序、toLowerCase折叠档与代表元取首现写法,关掉去重后并集从3行涨到6行,守恒与幂等同时翻面。

四个开关里,默认开着的是哪三个

四个开关的默认态我没核实过——起因是一轮并集结果比预期多出一截,回头发现「结果去重」被取消过勾选。于是把模板拆下来:本体 8641 字节、215 个换行,脚本正文 4630 码元按 LF 切出 146 段,一字不改跑在 DOM 桩上。读出来的 markup:opt-trim、opt-skip-empty、opt-dedup 三条都带 checked,唯独 opt-case 不带——默认就是「去首尾空格 + 忽略空行 + 结果去重 + 不区分大小写」,currentOp 初值逐字是 intersection。名单样本一律是 DEMO- 前缀的虚构编号。

这套默认值在 文本集合运算 页管着三件事:大小写档位决定 Apple 和 apple 算不算同一个元素;trim 与忽略空行决定「看着非空」的行算不算元素;结果去重不只作用在结果层,还喂着 parseSet 的第 5 步。整页 textarea 2 个、tab 3 个、checkbox 4 个、下拉 0 个,动哪个都全量重算。

parseSet 的五步顺序,与「代表元取首现」

顺序是:按换行切开 → trim 开着就改写该行 → 改写后是空串且忽略空行开着就跳过 → key 取该行或它的 toLowerCase → 去重开着才查 seen → 最后 push 的是改写后但未折叠的那一行。最后半句就是代表元规则:「Apple / apple / APPLE」3 行默认档 cnt-a=1,数组就是 ["Apple"];勾上区分大小写才变 3。

A=「Apple / apple / DEMO-7」、B=「apple / Apple / DEMO-8」,交集是 ["Apple"],取 A 侧首现写法;两侧对调,结果变成 ["apple"]。并集先把整个 A 的首现序推完,再接 B 里没出现过的。「差集有方向」那套讲法在旧文 对比两份名单 写过,本篇不重讲。

折叠只用 toLowerCase() 一个函数

模板里 toLowerCase 命中 7 次、toLocaleLowerCase 与 toUpperCase 各 0 次,后果分三类。一类正常并:ß 与 ẞ 都折成 U+00DF 同 key,「ß / ẞ / ss / ß」4 行得 cnt-a=2,ss 折后是 2 个码元、不并。二类不并:İ 折成 i 加 U+0307 组合点、共 2 个码元,UTF-8 从 2 字节变 3 字节,所以 İ 与 I、i 的 key 不相等——「İ / I / i / İIII」4 行默认档 cnt-a=3,数组是 ["İ", "I", "İIII"],I 与 i 并成一个。三类:开尔文符号 U+212A 折成 k,「U+212A / K / k」3 行 cnt-a=1,代表元取首现那个 3 字节的原始写法;ẛ 折完原地不动。「默认不区分大小写」不等于所有变体都并上。

关掉结果去重,那条短路整条失效

parseSet 里那行 if (dedup && seen.has(key)) continue 在去重关时整条短路,折叠层与结果层去重一起失效。固定 A=「apple / Apple / APPLE / DEMO-X」4 行(前三行折叠后同 key)、B=「apple / BANANA」2 行,只切这一个开关:

档位cnt-a交集差集并集
去重开(默认)2113
去重关4316

差集两档都是 1,因为 A 里不在 B 的只有 DEMO-X;交集 1 涨到 3 是 apple 三种写法全留;并集 3 涨到 6,那块 innerHTML 实测 542 码元。规模版:A、B 各 1000 行、重叠 500,去重开并集 1500,正好 1000+1000−500;关掉变 2000,守恒差 500。所以列表页 intro「合并两个列表并去重(A∪B)」与页面说明的「合并去重」只在勾选着去重时成立,引用并集计数必须注明档位。

把结果整段粘回 A 再算:去重开时三档第 2 轮与第 1 轮逐字相同;去重关时并集不收敛,连粘 4 轮 cnt-r 走 6、8、10、12,每轮净增的 2 行恰好等于 cnt-b。

只切「结果去重」:A 4 行、B 2 行 去重开 cnt-a 2、交 1、差 1、并 3 去重关 cnt-a 4、交 3、差 1、并 6,innerHTML 542 粘回 A 连跑并集(关) cnt-r 6、8、10、12,每轮净增 2

图 1:守恒与幂等都挂在同一个勾选框上

cnt-a 报的不是输入框的行数

三个统计格显示的都是 parseSet 之后的数组长度,不是 textarea 的行数。「段数」指按换行切开的份数(B 留空,其余默认):

输入(A 侧)段数非空行默认 cnt-a忽略空行关
两行编号、无尾随换行2222
同两行、末尾多一个换行3223
两行编号加中间空行与尾随换行4223
中间一行只有 2 个全角空格 U+30003323
4 行纯空白(空格、制表符、全角空格、NBSP)4401

尾随换行多出的空段,只在关掉忽略空行后才被计成元素;4 行全空白在默认档 cnt-a=0,整个 A 变空集,「非空行=4」与「cnt-a=0」同屏。NBSP(U+00A0)与 BOM(U+FEFF)都被 trim 清零。

空集合 ∅ 那一支,和没被清掉的上一轮

结果数组长度为零时脚本连做三件事:结果卡 display 成 none、空态块显示、文案覆写成「运算结果为空集合 ∅」——这句 10 个码元、28 字节,∅ 是 U+2205、占 1 码元 3 字节。模板末尾裸调的那次 calc 在首屏就把两个空框推进这个分支,markup 里那句 15 码元的「请在上方输入集合元素后自动计算」在被看见之前就遭覆写,此后没有任何代码写回。

∅ 分支还不清空结果区的 innerHTML:先算出 1 行结果(innerHTML 长 94 码元),再改输入让交集变 ∅,cnt-r 归 0、结果卡已隐藏,此时点「复制结果」仍带走上一轮那 1 行 DEMO-0001——隐藏不等于清空。escHtml 按 &、<、>、" 四组顺序替换(& 排第一,保住往返),<b> 行显示与复制都是字面 <b>;「<b> / a&b / "q"」3 行样本 innerHTML 284 码元,复制串 11 码元、含 2 个换行。500 行结果的 innerHTML 实测 47892 码元、序号占 1392 码元、末行 #500;scrollHeight 未实测——本次全程纯 Node,没有排版引擎。这些档位只属于本页代码,别外推成所有集合运算工具都长这样。

FAQ

Q:并集行数比名单的元素数还多,是页面出错了吗?

不是。先核对 opt-dedup 勾选框状态,再对照上面那张两档表。

Q:Apple 和 apple 都在,最后留下哪一个?

留 A 侧首现的原始写法,对调后得 ["apple"]。前提是区分大小写没勾。

Q:只想去重、不做交并差呢?

另一页 文本排序去重 更贴近这个需求;它自己的折叠口径这次没测,不替它下结论。

📎 相关文章

奶奶要连点三下才出来:亲戚关系计算器 36 条规则与 11110 条链的兜底实测 2026-11-07 口算题卡每张 A4 能排多少题:字号、页边距与信息栏怎么改分页 2026-11-03 同一串 23 字节的内容切换 4 个纠错等级:这一页自己的二维码编码器走到了哪一步 2026-10-30 帧间隔填 137 ms,成品每帧其实停 140 ms:tick 量化、4096 页填充与跟着第一张走的画布 2026-10-30 拼豆图纸的色号是怎么挑出来的:开一次抖动,1024 格里有 150 格被改写 2026-10-30