使用方法
- 把要重复的文字粘进左侧「要重复的文本」。示例已预填
柳泉工具四个字,直接点按钮就能看到结果。 - 在「重复次数」填 1 ~ 100000 的整数,示例值 5;在「分隔符」选换行、空格、逗号加空格、顿号、竖线或无分隔符。
- 需要区分每一份时把「序号前缀」设为两位补零,输出会变成
01. 柳泉工具这样的形式;不想有编号就选"不编号"。 - 原文本身是多行时,用「原文换行处理」决定是原样保留成多行块,还是压成一行。压成一行时,原文里的换行会被替换成分隔符,不会残留断行。
- 在文本框里按
Ctrl + Enter(Mac 是Cmd + Enter)触发;普通 Enter 保留给换行。下方对照表默认 12 行,点「加载更多行」展开。
这个文本重复器能解决什么问题
文本重复器的核心场景是批量生成格式规整、份数明确的内容:给同事发一条消息要重复三遍显得诚意、测试表单要灌 200 条相同记录占位、做压测时准备固定内容的请求体、给 Markdown 表格或测试用例列表补上带序号的行、给批量导入模板准备 1000 行示例。这些活儿用 Excel 拉填充柄做不了——Excel 拉不出"每份带独立序号"的结果,手工复制粘贴 1000 次也不现实。
它和"复制粘贴"的关键差别在可核算。文本重复器给出的不是一坨文本,而是四个可以核对的数:输出字符数(UTF-16 单元)、码点数、行数、以及按当前分隔符算出的精确公式值。你在别处粘贴之后如果发现少了几行,能立刻反推是分隔符宽度算错了还是原文里有不可见字符。
本页不做的事:不帮你改写每份内容的措辞(那是文本清洗和查找替换的活儿),也不做大小写或全半角转换。同样地,本页不统计字数和字符数——文本重复器只负责"生成"这一步,生成完想知道结果多长,翻到本页给出的对照表和长度卡片即可,不必跳去别的页面。
拼接算法与长度公式
核心就一行:new Array(n).fill(text).join(sep)。
- 为什么不用
text.repeat(n):String.prototype.repeat(ES2015,ECMA-262 第 21.1.3.1 节)只能把原串首尾相连,中间插不进分隔符。对"柳泉工具"重复 5 次,repeat得到的是 20 字符的连写串,而带换行的版本是 24 字符——差的 4 个正是 4 个换行符(n−1 个,不是 n 个)。 - 为什么用
fill再join而不是循环拼接字符串:s += t + sep在 V8 里靠"rope"( ConsString)优化,短串看不出差别,但join一次分配最终缓冲,行为可预测,且当 n 大时不会把中间字符串全部驻留。new Array(n)传非整数会直接抛RangeError: Invalid array length,所以页面的次数只收整数。 - 输出长度的精确公式:
L = n × S + (n − 1) × P,其中 S 是原文字符数、P 是分隔符字符数、序号前缀另计。用示例核对:n=5、S=4、P=1 → 5×4 + 4×1 = 24,与页面实测一致。把 P 换成"逗号+空格"(2 字符)→ 5×4 + 4×2 = 28。 - 序号前缀用
String.prototype.padStart:两位补零时每条前缀恒为 4 字符("01. "),5 条共 20 字符,与不带序号的 24 相加得 44。用 padStart 而不是切片,是为了让第 9 条和第 10 条宽度一致,粘贴成表格时不会错位。 - 码点数用
Array.from(str).length:String.length数的是 UTF-16 单元,不是"人看到的字"。emoji U+1F600 在字符串里由高代理U+D83D和低代理U+DE00两个单元组成,length返回 2,而Array.from返回 1。重复 3 次后 length 是 6、码点数是 3。中文"柳"在基本多文种平面内,两者相同(都是 1),所以这个差异只在 emoji 和部分生僻字上暴露。
完整示例(数值仅作演示)
示例条件(与页面默认值完全一致):原文 柳泉工具(4 字符),次数 5,分隔符换行(1 字符),序号前缀选"不编号"。
- 输出长度 = 5 × 4 + 4 × 1 = 24 字符,码点数 24,行数 5。这就是打开页面时输出框里已经有的内容。
- 把序号前缀改成"两位补零"后,每条前缀恒为 4 字符("01. "),5 条共 20 字符,输出长度 = 24 + 20 = 44 字符。首行
01. 柳泉工具,末行05. 柳泉工具。 - 把分隔符换成"逗号 + 空格"(2 字符)后长度 = 20 + 8 = 28 字符;换成无分隔符 = 5 × 4 = 20 字符,恰好等于
repeat(5)的结果。
第一个示例更贴近实际使用:一行 待办- 重复 12 次并加两位序号,每行 01. 待办- 恒为 7 字符,12 行加 11 个换行 = 7 × 12 + 11 = 95 字符。这个实测值与下面对照表里"待办-"那一行逐位一致,可以直接对表核对。
以上数字用于演示长度计算,不代表任何真实数据。
次数与输出长度对照表
下表按示例原文(4 字符)和换行分隔符算出,公式是 5n − 1。表格同时给出按当前设置实际能跑到的最大次数,超过 20 万字符会被拒绝。
| 重复次数 n | 输出字符数 | 输出码点数 | 行数 | 带序号后长度 | UTF-8 体积(中文字符) | 是否可生成 |
|---|---|---|---|---|---|---|
| 1 | 4 | 4 | 1 | 8 | 12 B | 可 |
| 2 | 9 | 9 | 2 | 17 | 27 B | 可 |
| 3 | 14 | 14 | 3 | 26 | 42 B | 可 |
| 5 | 24 | 24 | 5 | 44 | 72 B | 可 |
| 10 | 49 | 49 | 10 | 89 | 147 B | 可 |
| 20 | 99 | 99 | 20 | 179 | 297 B | 可 |
| 50 | 249 | 249 | 50 | 449 | 747 B | 可 |
| 100 | 499 | 499 | 100 | 899 | 1497 B | 可 |
| 500 | 2499 | 2499 | 500 | 4499 | 7497 B | 可 |
| 1000 | 4999 | 4999 | 1000 | 8999 | 14997 B | 可 |
| 5000 | 24999 | 24999 | 5000 | 44999 | 74997 B | 可 |
| 20000 | 99999 | 99999 | 20000 | 179999 | 299997 B | 可 |
| 40000 | 199999 | 199999 | 40000 | 359999 | 599997 B | 可(贴上限) |
注意最后一列的"UTF-8 体积"按中文字符每个 3 字节算。20 万个中文字符实际是 600000 字节,也就是约 585.9 KB;换成 emoji(每个 4 字节)会到 800000 字节、约 781.3 KB。所以"20 万字符"在磁盘上的体积可以是 390 KB 也可以是 780 KB,取决于内容是什么。
边界与精度
- 次数下限 1:
repeat(0)和new Array(0).fill().join()都返回空串,长度 0。0 次在语义上就是"什么都没生成",没有可展示的结果,所以文本重复器把下限锁死在 1 而不是让它返回空白。 - 次数上限 100000、原文上限 10000 单元:两者独立校验。原文超长时先提示原文超限,而不是让它把输出撑爆后再报输出超限。
- 输出上限 200000 字符(UTF-16 单元):超过就拒绝,并在提示里直接给出当前设置下能跑到的最大次数。这个值远低于引擎硬上限——V8 实测最大字符串长度是 536870888(正好是 229 − 24),越过就抛
RangeError: Invalid string length。本页设 20 万不是引擎限制,而是一次把几十万字符塞进<textarea>会让标签页滚动和选区操作明显卡顿。 - 超限时怎么算最大次数:由
n×S + (n−1)×P ≤ 200000解出n ≤ (200000 + P) ÷ (S + P + 序号宽度),向下取整。用 4 字原文配换行(无序号)验证:n=40000 时 40000×4 + 39999 = 199999,刚好在限内;n=40001 时是 200004,超限。同样的原文填 100000 次会算出 499999 字符——注意这里 n×S 是乘法不是加法,100000 份 4 字文本是 50 万字符量级,不是 10 万。10 字原文则是另一组解:n ≤ 200001 ÷ 11 = 18181.9,取 18181 时输出 199990 字符。 - 精度的三个口径不要混:
String.length(UTF-16 单元)、Array.from(s).length(码点)、[...s].length(码点,与前者等价但对孤立代理项行为不同)。页面三个数都给出,缺一不可——只报 length 会让你以为 emoji 占两个字。 - 表格只渲染前 12 行:n=100000 时结果有 10 万行,全量塞进 DOM 会让浏览器卡死。表格只渲染当前可见行,完整结果通过「复制结果」或「导出 CSV」拿。序列长度截断同理,只在提示里注明总数。
常见问题
为什么分隔符是 n−1 个而不是 n 个?
因为分隔符是"夹在两份之间",不是"每份后面都跟一个"。n 份之间只有 n−1 个缝隙。用示例核对:5 份 4 字文本、换行分隔,5 × 4 = 20 加 4 个换行 = 24。如果错误地按 5 个换行算,会得到 25,比实际多 1——重复次数越多误差累积越明显,n=1000 时会差 999 个字符。
状态里"字符数"和"码点数"为什么对不上?
因为 emoji 占了 2 个 UTF-16 单元但只有 1 个码点。U+1F600 存成代理对 D83D + DE00,length 数出 2,Array.from 数出 1。重复 3 次后分别是 6 和 3。中文"柳"在基本多文种平面内,length 和码点数都是 1,所以差异只在 emoji 和生僻字上暴露。这不是 bug,是 UTF-16 编码的历史设计——它诞生时 UCS-2 只有 16 位,装不下 emoji。
次数填 50000 报错,是不是次数上限太小了?
不是次数的问题,是输出长度。次数上限是 100000,但输出上限 200000 字符往往先撞上。同样填 50000 次:原文 1 个字算出 50000×1 + 49999 = 99999 字符,能过;原文 2 个字是 149999,也能过;原文 4 个字就是 249999,超限被拒。原文 1 个字时最多能填到 floor(200001 ÷ 2) = 100000 次,正好等于次数上限,所以次数上限很少是真正的瓶颈——原文长度才是。想突破只能减少原文长度或换更窄的分隔符。
无分隔符和空格分隔符,粘贴到记事本里看起来一样,为什么长度不同?
因为空格本身就是分隔符。无分隔符时 5 份直接相连,长度 20;空格分隔符是 5×4 + 4×1 = 24,差的 4 个是看不见的空格。视觉上分不出不代表数据相同——把两段文本粘进编辑器搜空格就能发现区别。这也是为什么页面把两个数都列出来而不是只给你看结果。
用加序号模式后,怎么保证第 100 条和第 9 条对齐?
靠 padStart。文本重复器的两位补零把序号统一补成 "01" 到 "100",宽度恒定;"01. " 前缀含句点和空格共 4 字符,和"99. "一样宽。如果只用自然序号不补零,第 9 条是"9. "(3 字符)而第 10 条是"10. "(4 字符),粘进表格必然错位一行。三位补零则保证 1000 条以内不错位。
原文里的换行符为什么有时会改变结果?
因为分隔符和原文换行会被拼在一起,各算各的。原文"甲\n乙"(3 字符:甲、换行、乙)重复 2 次用换行分隔,输出是 3 + 1 + 3 = 7 字符、行数 3 而不是 2——中间那个换行和分隔用的换行混在一起,看起来像多了一行。选"压成一行"把原文换行替换成分隔符,这个混淆就消失了。
CSV 导出为什么开头有一段看不见的字符?
那是 UTF-8 BOM(U+FEFF),3 字节。Excel 打开不带 BOM 的 UTF-8 CSV 会把中文识别成乱码,加上 BOM 就能正确识别。命令行工具如 awk、cut 不会跳过它,会把 BOM 当成第一个字段的第一个字符——这是刻意的取舍:优先保证 Excel 用户双击就能看。
这个工具免费吗?数据安全吗?
免费,无需注册即可使用。全部处理在当前浏览器内完成,不发任何网络请求,可以在开发者工具的 Network 面板自查(应为空)。刷新页面后输入即清空,不写入 localStorage。