字数统计工具

统计字符、单词、句子等

0
字符
0
字符(不含空格)
0
单词
0
句子
0
段落
0

码元、码点、字素:同一个字符串的三种长度

问"这个字符串有多长?",JavaScript、Unicode 和用户会给出三个不同的数字。String.prototype.length 数的是 UTF-16 码元 — JavaScript 内部编码的 16 位单元。所有基本多文种平面(BMP)之外的字符都以代理对(surrogate pair)存储,所以肉眼看是一个符号,'👍'.length 却是 2。 对字符串做展开([...s])则按码点迭代,解决了代理对问题,但解决不了序列问题。家庭 emoji 👨‍👩‍👧‍👦 是 4 个人物码点用 3 个零宽连接符(U+200D)缝在一起:length 为 11,码点数为 7,可见的字形却只有 1 个。国旗是 2 个 regional indicator 符号 — 🇰🇷 的 length 是 4。肤色修饰符又在基础 emoji 上再叠一个码点。 用户感知的单位是字素簇(grapheme cluster),而且从 2021 年起平台可以原生统计:granularity 设为 'grapheme' 的 Intl.Segmenter 按文本光标移动的方式精确切分字符串。字符计数器展示"用户看到的字符数"时,应该用的就是这个数字。 后端还会加上第四把尺子。MySQL utf8mb4 的 VARCHAR(10) 按码点计数,Postgres 的 varchar(10) 也是;但按字节限制的 API 把每个 CJK 字符看作 3 个 UTF-8 字节、每个 emoji 看作 4 个。同一段日文可以在 JS 的 length 检查里没超限,在按字节计数的后端却超限了。永远用执行限制的那个系统的尺子来校验。
const fam = '👨‍👩‍👧‍👦';
fam.length                      // 11 UTF-16 code units
[...fam].length                 // 7 code points (4 people + 3 ZWJ)
const seg = new Intl.Segmenter('en', { granularity: 'grapheme' });
[...seg.segment(fam)].length    // 1 — what the user sees

'👍'.length                     // 2 — surrogate pair
'🇰🇷'.length                     // 4 — two regional indicators

平台限制解码:Twitter 的 280、短信的 160、Google 的 600 像素

现实世界的限制很少是纯字符数。Twitter/X 允许 280 个加权单位:多数拉丁字母、数字和标点权重为 1,而 CJK 字符、emoji 等宽字符范围权重为 2 — 所以一条日文推文最多 140 个字。URL 无论实际多长,一律按 23 个单位计费,因为 t.co 包装把长度归一化了。 短信更古怪。整条文本若都落在 GSM-7 字母表内,一条短信容纳 160 个字符。只要有一个字符越界 — 一个 emoji、一个从文字处理器粘来的弯引号、某些带重音的字母 — 整条消息就静默切换为 UCS-2,额度骤降到 70。长消息被拆成级联(concatenated)分段,每段要牺牲头部字节,GSM-7 剩每段 153 字、UCS-2 剩 67 字。一个智能引号能把一条计费短信变成三条 — 批量短信账单经常暴露这个问题。 其他平台:Instagram 文案上限 2,200 字符、30 个话题标签。Google 按渲染后的像素宽度截断标题 — 约 600px,依字母宽窄大致相当于 50–60 个字符(WWW 比 iii 宽得多)— meta description 大约在 155–160 字符。实务结论:先弄清目标系统数的是码元、加权单位、GSM-7 septet 还是像素,再用有代表性的真实文本测试,而不是 lorem ipsum。

数单词依赖语言 — CJK 打破了空格规则

按空格切分,在英语、德语、西班牙语里是可靠的单词计数器。但对任何一句中文或日文,它都精确地返回 1 — 这些文字书写时没有空格。CJK 真正的分词需要词典或统计模型:日语的标准形态素分析器是 MeCab,中文用 jieba,浏览器里则有 granularity 设为 'word' 的 Intl.Segmenter,零依赖地暴露 ICU 的词典分词。 韩语介于两者之间:它确实用空格,但间隔的单位是"어절"(词+助词的组合),所以按空格计数得到的是어절数而非词典意义上的单词。实践中韩文反正按字数计量 — 这是从 200 字稿纸(원고지)传统继承的惯例,学校和出版界至今沿用。 这个区别直接关联到钱。专业翻译对英语类语言按源语单词计费,对日文中文按字符计费;跨语言报价时,翻译公司会套用公开的换算系数 — 量级大约是每个英文单词折合两个 CJK 字符。学术和法律的篇幅限制同样分裂:日文期刊规定字数,英文期刊规定单词数。 如果你的产品要向多语言用户展示单词数,请统计 Intl.Segmenter 里 isWordLike 的分段;同一条代码路径就能对英语和 CJK 都给出语言学上合理的数字。
function countWords(text, locale = 'en') {
  const seg = new Intl.Segmenter(locale, { granularity: 'word' });
  return [...seg.segment(text)].filter(s => s.isWordLike).length;
}

countWords('The quick brown fox');            // 4
countWords('日本語は分かち書きをしない', 'ja');  // dictionary-segmented
'日本語は分かち書きをしない'.split(/\s+/).length; // 1 — naive split fails

NFC 与 NFD:像素不变、计数却变的规范化

Unicode 里同一段可见文本常常有不止一种编码。韩文音节 한 既可以是一个预组合码点(U+D55C),也可以是三个组合字母(初声 ᄒ、中声 ᅡ、终声 ᆫ);é 则是单码点 U+00E9,或者是 e 后面跟组合尖音符 U+0301。NFC 是组合形式,NFD 是分解形式。二者渲染出的像素完全相同,比较结果却不相等。 在 Mac 上这不是纸上谈兵。HFS+ 以分解形式的变体存储文件名,macOS 的一些界面至今仍会递给你 NFD 文本 — 从 Finder 复制一个韩文文件名贴进计数器,한글.txt 会报 10 个字符而不是 6 个。从 macOS 上传的文件名同理:后端的 maxlength 校验可能放行手动输入的文本,却拒绝看起来一模一样的粘贴文本。 第二个症状是相等性:当一侧是 NFC、另一侧是 NFD 时,'é' === 'é' 可能为 false,这会悄悄破坏去重、搜索匹配和唯一性约束。修复只要一行 — 在计数、比较或哈希之前调用 str.normalize('NFC');规范化是幂等且快速的。通过 Intl.Segmenter 做字素簇计数则基本免疫,因为 한 的两种编码都构成同一个簇 — 这也是"凡是给人看的数字就数字素"的又一个理由。
const nfc = '한'.normalize('NFC');  // U+D55C
const nfd = '한'.normalize('NFD');  // U+1112 U+1161 U+11AB
nfc.length              // 1
nfd.length              // 3 — same pixels, three code units
nfc === nfd             // false

'한글.txt'.normalize('NFD').length  // 10
'한글.txt'.normalize('NFC').length  // 6

阅读时间的数学:每分钟 238 词及其他有依据的数字

阅读时间估算看似拍脑袋,其实有实测的锚点。Brysbaert 2019 年的元分析(近 190 项研究)把英语非虚构类的默读速度定在每分钟约 238 词,虚构类稍快,约 260。Medium 的阅读时长算法用 265 wpm,并为第一张图片加 12 秒,之后每张递减 1 秒,最低 3 秒。日文和中文的规划数字则按字符报 — 舒适默读大约每分钟 400 到 600 字。 平均词长让换算成为可能。英语平均每词约 4.7 个字母,算上后面的空格约 5.7 个字符,所以一篇 1,000 词的文章约 5,700 字符,按 238 wpm 四分钟出头读完。同样的算术可以翻译各种限制:155 字符的 meta description 约容纳 25 个英文单词;160 字符的 GSM-7 短信约 28 个。 口播远慢于默读 — 旁白和会议演讲在每分钟 130 到 150 词左右 — 这就是"五分钟阅读"的文章会变成九分钟配音稿的原因。密度也是有用的编辑信号:如果平均词长明显超过 6 个字母,说明文本术语密集,实际阅读会比任何按词计算的公式预测的更慢。
最后更新:

关于此工具

字符与单词计数器实时统计文本的字符(含/不含空格)、单词、句子、段落、行数。适合推文、Meta 描述、应用商店文案等有字数上限的内容,以及以字数为成果指标的写作和翻译工作。

使用方法

  1. Paste or type your text into the input box.
  2. All six metrics update on every keystroke — no button needed.
  3. Use the characters-without-spaces value when comparing against APIs that count code points.
  4. Watch the words count for blog posts, essays, and content with a target length.
  5. Use line count when working with logs, source code, or CSV-like data.

常见用例

  • Checking that an SEO meta description stays under 160 characters.
  • Hitting a 280-character limit for a Tweet or 300-character limit for a Bluesky post.
  • Tracking word count for academic essays or magazine assignments.
  • Estimating reading time (~200 words per minute) for a blog post.
  • Auditing log file size by line count when piping output into the textarea.
  • Validating user-generated content against backend length constraints before submitting.

常见问题

Q. How are words counted?

A. By splitting on whitespace runs after trimming. So "hello world" = 2 words, but "hello world" (multiple spaces) is also 2.

Q. Why is character count different from what Twitter shows?

A. Twitter weights certain characters (like emoji and CJK) differently. This tool reports raw JavaScript string length (UTF-16 code units), which matches most backend validations.

Q. How are sentences detected?

A. By counting end-of-sentence punctuation (. ! ?). Abbreviations like "Mr." may inflate the count slightly.

Q. Does the tool send my text anywhere?

A. No. Counting happens entirely in your browser; nothing is uploaded.