使用方法
- 把文本粘进上面的框,或直接输入。结果是实时更新的,页面打开时框里已有一段 6 行的示例,卡片上显示的就是它的结果。
- 看文本行数判断篇幅:示例是 6 行。这个数字已经按「末尾换行不额外算一行」的口径处理过。
- 看非空行(示例 5)与空白行(示例 1):第 4 行是空行,所以两者相加正好回到 6。
- 看最长行(示例 23 个字符)与平均行长(8.50),用来判断有没有某一行特别长、需不需要折行。
- 看换行符总数(示例 5)以及下方提示里的 CRLF / LF 拆分,确认文本是从哪个系统复制来的。
- 点「复制统计结果」带走六项指标;「载入示例」还原样例,「清空文本」清空,输入框里按 Ctrl + Enter 可跳过延迟立刻重算。
这个行统计能解决什么问题
一是核对「行数对不上」。同一份名单在一个系统显示 120 行、另一个显示 121 行,绝大多数情况是末尾那个换行符被当成了空行。本页把「文本行数」和「split 长度」两个口径同时摆出来,一眼就能看出差异来自哪里。
二是处理从 Windows Office 粘过来的数据。Windows 记事本、Excel 复制的多行文本用的是 CRLF(回车加换行),纯 \n 切分会把 \r 留在行尾,最长行、平均行长都会整体偏大。本页先做换行归一,再把 CRLF、LF、单独 CR 三类换行符分别报数。
三是清理粘贴带来的空白行。空白行数一栏直接告诉你混进来几行空内容;要把它们删掉,可以用页面下方的「删除空行」工具,不用手动一行行找。
四是给排版和导入做体检。导入 CSV 前先看行数和最长行,能提前发现多余换行、断裂的记录;日志文件按行统计总行数,也常用作数据量的粗略刻度。
本页不做这些事:不统计汉字、单词、句子和段落(那些是另一个口径,请用「字数统计工具」);不按字节算长度(请用「字符数统计工具」);也不修改文本本身,去空行、去重复行都有专门的工具。
统计原理:按行拆分的三种口径
第一步是把换行归一。本页用 x.split(/\r\n|\r|\n/) 切行,而不是常见的 x.split('\n')。差别在 CRLF:Windows 文本的换行是两个字符 \r\n,若只按 \n 切,每一行末尾都会留下一个不可见的 \r,于是 第一行 会变成 第一行\r,最长行长度从 3 变成 4。正则的写法里 \r\n 必须放在最前面,否则 \r 会先把 CRLF 拆成两段,反而多切一次。
第二步是区分「split 长度」与「文本行数」。这是行统计最容易踩的坑:'a\nb\n'.split('\n') 得到 ['a', 'b', ''],长度是 3,但这份文本其实只有 2 行——最后那个空字符串只是因为字符串以换行符结尾。本页的「文本行数」按后者算:若最后一个元素是空串,就把它减掉;若文本本身是空串,则算 0 行。这也是为什么空串的 split 长度是 1、文本行数却是 0。
第三步是判定空白行。用 L[i].trim() === '' 判断:只含空格、制表符的行按空白行计,但仍占一行。示例文本第 4 行是真正的空行,第 10 行对照里的 \n 则是两行「只有空格的行」,两者都计入文本行数、都不计入非空行。
换行符计数分开做三档。LF 用 /\n/g,CRLF 用 /\r\n/g,单独 CR 用 /\r(?!\n)/g(负向前瞻,确保这个 \r 后面不是 \n)。总数 = 单独的 LF + CRLF + 单独的 CR。这样报出来的数字既不会把 CRLF 里的 \n 重复计一次,也不会漏掉老 Mac 文本里的孤立 \r。
行长按 Unicode 码点算。用 Array.from(line).length 而不是 line.length:JavaScript 字符串以 UTF-16 存储,一个 emoji 或扩展区生僻字占 2 个码元却只有 1 个码点。行统计关心的是「这一行看起来有多长」,用码点更贴近直觉;若你要的是存储字节数,那属于另一套口径。换行符依据的是 Unicode 的行终结符定义,ECMAScript 的字符串语义由 ECMA-262 规定,两者都不随版本频繁变动,可以照页面上的写法自行复核。
完整示例(数值仅作演示)
示例条件就是页面打开时框里那段文字,共 6 行、中间夹一行空行、结尾不带换行符。复算结果如下:
- 文本行数 6、非空行 5、空白行 1;
- 最长行 23 个字符,出现在第 2 行「第 2 行故意写长一点,用来演示最长行的口径。」;
- 平均行长 8.50,即 6 行长度之和 51 除以 6;
- 换行符总数 5,全部是 LF,CRLF 与单独 CR 均为 0;
- 因为结尾没有换行符,所以
split(/\r\n|\r|\n/)的长度也是 6,与文本行数相等,末尾没有多出空元素。
逐行长度可以手工对一遍:第 1 行 7、第 2 行 23、第 3 行 6、第 4 行 0、第 5 行 5、第 6 行 10,合计 51,最长 23,平均 51 ÷ 6 = 8.50。两个边界例子更能说明口径:a\nb\n 的 split 长度是 3 而文本行数只有 2;从记事本复制的三行文本 第一行\r\n第二行\r\n第三行,若错误地按 \n 切,最长行会从 3 变成 4——多的就是那个残留的 \r。
换行写法与统计口径对照表
下表把常见文本片段的统计结果列出,split 长度 是按 \n 直接切分的直观值,文本行数 是本页采用的规范口径。两列不一致时,以「文本行数」为准。
| 文本片段 | split 长度 | 文本行数 | 非空行 | 最长行 | 说明 |
|---|---|---|---|---|---|
空串 | 1 | 0 | 0 | 0 | 空串按文本行数算 0 行,split 却给出 1 个空元素 |
a | 1 | 1 | 1 | 1 | 没有换行符,就是 1 行 |
a\n | 2 | 1 | 1 | 1 | 末尾换行只说明第 1 行已终止,不新增空行 |
a\nb | 2 | 2 | 2 | 1 | 无终止符,两行都是完整行 |
a\nb\n | 3 | 2 | 2 | 1 | 与 a\nb 行数相同,split 却多出一个空元素 |
a\nb\nc | 3 | 3 | 3 | 1 | 两个换行符对应 3 行 |
\n | 2 | 1 | 0 | 0 | 一个空行,split 得到 2 个空元素 |
\n\n | 3 | 2 | 0 | 0 | 两个空行 |
a\n\nb | 3 | 3 | 2 | 1 | 中间是空白行,非空行只有 2 |
\n | 2 | 2 | 0 | 3 | 只有空格的行算空白行,但仍计入文本行数 |
a\r\nb | 2 | 2 | 2 | 1 | CRLF 若只按 \n 切,首行会残留 \r 让最长行多 1 |
a\r\nb\r\n | 3 | 2 | 2 | 1 | CRLF 同样多出末尾空元素,行数口径不变 |
再看换行符本身的对照。识别出用的是哪一种换行,是判断文本来源最快的方法:
| 换行写法 | 字符 | 典型来源 | 只按 \n 切会怎样 |
|---|---|---|---|
| LF | \n(U+000A) | Linux、macOS、多数网络协议 | 正常,行尾无残留 |
| CRLF | \r\n(U+000D U+000A) | Windows、记事本、Excel 复制、HTTP 头 | 每行尾部残留 \r,行长整体 +1 |
| CR | \r(U+000D) | 经典 Mac OS 9 及更早 | 整段被当成一行,行数严重偏少 |
输入范围、边界与精度说明
- 文本上限 100 万字符(输入框的
maxlength,按 UTF-16 码元计)。纯汉字能装 100 万个,纯表情只能装约 50 万个。超过 50 万字符时输入会有一点延迟,按 Ctrl + Enter 可立刻重算一次。 - 空文本时六项全是 0,包括空白行与最长行;页面不会给出「1 行」这种看着就不对的默认值,而是显示一段说明,告诉你 split 长度为何是 1。
- 「文本行数」与「split 长度」相差最多 1。差值恰好为 1 当且仅当文本以换行符结尾;若结尾没有换行符,两者相等。这正是「末尾要不要算一行」这个争议的全部来源。
- 只有空白时不算非空行,但仍算行。三个空格加一个换行,结果是「文本行数 2、非空行 0、空白行 2、最长行 3」。
- 行长按码点计,一个 emoji 算 1。用
Array.from(line).length。若你要的是数据库字段能装多少字节,那是 UTF-8 字节口径,一个汉字 3 字节、一个 emoji 4 字节,请用字符数统计工具。 - CR 单独出现时按一次换行处理。老 Mac 文本用孤立
\r表示换行,正则里的\r分支专门兜住它;不处理的话整段会被算成 1 行。 - 不做 Unicode 其他行终结符。Unicode 还定义了 U+2028 行分隔符与 U+2029 段分隔符,但它们极少出现在普通文本里,本页不把它们当换行,以免把某些特殊字符内容误切。
- 不改动你的文本。归一化只在内存里做一份副本用于统计,输入框里的原文原样保留,也不会写回或上传。
常见问题
为什么行数比我在编辑器里看到的多 1?
多半是末尾多了个换行符。很多编辑器不显示行尾换行,但文本其实以 \n 结尾,某些统计方式会把最后那个空串也算成一行。本页的「文本行数」不会把它算进去:结尾有换行时,split 长度是行数加 1,我们把这个多出来的空元素减掉。对照表里 a\nb 与 a\nb\n 两行就能看出这一点。
从 Excel 或记事本复制过来,最长行怎么变长了?
因为那些文本用的是 CRLF 换行。若只按 \n 切分,每一行末尾都会留一个不可见的 \r,行长整体加 1。本页先用 /\r\n|\r|\n/ 归一,再统计,所以最长行、平均行长都不会被 \r 污染。下方提示里会单独报出 CRLF 的个数,方便你确认来源。
「文本行数」和「split 长度」到底该信哪个?
看你要回答什么问题。如果你问「这份文本有多少行内容」,用文本行数——它把末尾终止符造成的那一行排除掉。如果你问「按 \n 切开会得到几个数组元素」,用 split 长度。两者最多差 1,差值出现就说明文本以换行符结尾。本页把两个数都摆出来,就是让你按需要取用。
只有空格的行算不算空行?
算空白行,但仍计入文本行数。判定用的是 trim() 后是否为空,所以「三个空格」和「一个制表符」这样的行都归入空白行,不会进非空行。要把它们连同空行一起清掉,用「删除空行」工具即可。
换行符总数和行数是什么关系?
对结尾带换行的文本,换行符总数正好等于文本行数;对结尾不带换行的文本,换行符总数等于文本行数减 1。示例文本结尾没有换行,6 行对应 5 个换行符,正好符合这个关系,可以用它快速自查统计有没有跑偏。
一个表情或生僻字会让行长多算吗?
不会。行长按 Unicode 码点计,一个 emoji 只算 1。若按 JavaScript 的 line.length(UTF-16 码元)数,一个 emoji 会被算成 2。两种口径都有用途,本页选了更贴近「看起来多长」的码点口径,并在说明里注明。要按字节数衡量,请改用字符数统计工具。
它和字数、字符数统计有什么区别?
这个行统计只回答「行」的问题:多少行、几行是空的、最长行多长。字数统计工具数的是汉字、单词、段落,字符数统计工具数的是字符与字节。日志、名单、导入前的 CSV 这类以行为单位的数据,用行统计更快;文章投稿、文案字数核对,用字数统计更对。
文本会被上传或保存吗?
不会。六项指标全部由页面里的正则与字符串运算算出,没有任何网络请求,也不写入浏览器存储,刷新页面后输入框回到那段 6 行的预置示例。想自己确认,可以打开开发者工具的 Network 面板,边输入边看有没有请求发出。