关键词密度检测

同一个中文词,子串计数、Intl.Segmenter 词典分词、二元切分三种口径算出的密度能差 6.7 倍——因为「总词数」本身就取决于怎么切。本页把三种口径并排列出来,并标出哪个词超标。

留空则只统计词频榜,不算目标词密度
2 字起可排除「的 / 是 / 了」这类单字虚词
上限 6 字,超出常见中文词长
示例已服务端直出,脚本没跑也有内容;按 Ctrl/Cmd + Enter 触发,Enter 留给换行
目标词「密度」· 示例正文 202 汉字 / 30 个标点分段 / 143 个分词
① 子串 ÷ 标点分段   3 / 30  = 10.00%
② 子串 ÷ 汉字数     3 / 202 =  1.49%
③ 分词 ÷ 全部词     3 / 143 =  2.10%
④ 分词 ÷ 多字词     3 / 68  =  4.41%
⑤ 二元 ÷ bigram     3 / 201 =  1.49%
极差 8.51 个百分点,最高是最低的 6.7 倍

分词口径(Intl.Segmenter zh-Hans,粒度 word)
片段 174 个,其中 isWordLike 词 143 个:单字 75、多字 68,压缩比 0.708
「密度」作为完整词命中 3 次;「关键词」被切成「关键 / 词」,因此计 0 次
停用词表 83 条(中文 71 + 英文 24),过滤掉「不是 / 没有 / 所以 / 怎么」4 个后分母 68 → 63

(数值仅作演示;密度只是排查线索,不代表搜索引擎的实际评分)

分词口径词频榜(2~4 字、非停用词,示例正文)

词字数次数分词密度字符密度
关键234.76%1.49%
口径234.76%1.49%
密度234.76%1.49%
告诉223.17%0.99%
可能223.17%0.99%
目标223.17%0.99%
有人223.17%0.99%
重复223.17%0.99%
3.5323.17%0.99%
本身211.59%0.50%
标点211.59%0.50%
布局211.59%0.50%
常见211.59%0.50%
超过211.59%0.50%
承接211.59%0.50%
出现211.59%0.50%
除以211.59%0.50%
次数211.59%0.50%
低于211.59%0.50%
段落211.59%0.50%
堆砌211.59%0.50%
而是211.59%0.50%
二十211.59%0.50%
二元211.59%0.50%

使用方法

  1. 把中文正文粘进「正文」框(示例已服务端直出,202 个汉字)。关键词密度检测的读数完全取决于这一步怎么切。上限 200000 汉字,超出会被拒绝并提示实际字数。
  2. 在「目标关键词」填要盯的词(默认 密度,1~20 字符)。留空就只出词频榜,不算目标词密度。
  3. 调「词长下限 / 上限」(默认 2~4 字)。下限设 1 会把「的、了、是」这类单字虚词算进来,密度立刻虚高——本页把「的」单独列在正文里说明这件事。
  4. 点「检测密度」。上方六张卡是三种口径的分母与分子,下方是词频榜。按 Ctrl/Cmd + Enter 也能触发,Enter 留给换行。
  5. 榜里带蓝底的三行是当前目标词所在的行;点「导出词频表 CSV」可拿到带 BOM 的表格,Excel 打开不乱码。

这个关键词密度检测能解决什么问题

一是解释「为什么两个工具报的数字不一样」。同一段中文,A 工具说 4.41%、B 工具说 1.49%,两边都没算错——差别全在「总词数」怎么定义。本页把子串 ÷ 标点分段、子串 ÷ 汉字数、分词 ÷ 全部词、分词 ÷ 多字词、二元 ÷ bigram 五种分母一次列全,你在别处看到任何一个数,都能在这里找到它对应的口径。

二是揪出「看起来正常、其实超标」的词。示例正文里「关键」「口径」「密度」各出现 3 次,在分词口径下都是 4.76%,已经越过 3.5% 的经验上限;而同样三个词按字符密度算只有 1.49%,看起来毫无问题。两种读法指向完全不同的改稿动作。

三是看清「短文本的密度天生不稳」这件事。本文分母只有 63 个词,3.5% 对应的是「出现 2 次就超标」;而同样阈值放到 202 个汉字的分母上,允许出现 7 次。同一个 3.5%,在 200 字短文和 3000 字长文里完全不是一个尺度。

本页的关键词密度检测不做这些事:不判断你的密度「好不好」——它没有 Google's 排名数据,只有口径对照;不替代逐字统计,正文字数请用字数统计工具;也不算字符数(含标点空格),那是字符数统计工具的口径。本页只回答一件事:这个密度数字是怎么来的。

原理:中文没有空格,所以「总词数」有五种答案

口径①:子串计数 ÷ 标点分段。把文本按标点切成若干「段」,数目标词在原文里出现了几次(用 String.prototype.indexOf 做不重叠匹配,每次前进 needle 长度,避免「好好」在「好好好」里被数成 2 次)。分母是段数。这是最粗糙但最常见的做法:示例里 3 次 ÷ 30 段 = 10.00%,一篇文章里但凡出现两三个词就「超标」。

口径②:子串计数 ÷ 汉字数。分母换成 [\u4e00-\u9fff] 的匹配数。示例 3 ÷ 202 = 1.49%。这个口径把「词」等同于「字」,只有在中英文混排且英文占比极低时才勉强成立。

口径③与④:Intl.Segmenter 词典分词。这是 ECMA-402 定义的国际化分词接口,本页调用 new Intl.Segmenter('zh-Hans', { granularity: 'word' }),然后遍历 segment() 返回的片段,只保留 isWordLike === true 的片段——这一步会滤掉标点和空格,但保留数字与字母串(所以示例里的「3.5」也进了词表)。示例实测:174 个片段中 143 个 isWordLike,其中单字 75 个、多字 68 个,压缩比 143 ÷ 202 = 0.708。分母取全部词得 2.10%,只取多字词得 4.41%。

口径⑤:二元切分(bigram)。把纯汉字串的相邻两字配成词:密度 合成「密度」,「关键」合成「关键」。词数恒等于汉字数减一,没有分词歧义,也不需要词典——这是它在 Intl.Segmenter 不可用时作为回退方案的唯一理由。示例 3 ÷ 201 = 1.49%。

五种口径的极差是 8.51 个百分点,最高(10.00%)是最低(1.49%)的 6.7 倍。分子完全相同(都是 3 次),全部差异来自分母。这就是本页存在的理由:报密度不报口径,等于没报。

为什么分词口径会漏计,这是本页最实测的结论。逐个喂给 Intl.Segmenter:分词、自然、承接、堆砌、密度 都整词命中;而 关键词 被切成 ["关键","词"]、优化 被切成 ["优","化"]、搜索引擎 被切成 ["搜索","引擎"]、密度检测 被切成 ["密度","检测"]。V8 内置的 ICU 中文断词词典收录的是统计模型能独立成词的部分,对「关键 + 词」这种高频组合反而拆得更细。后果是:如果你把目标词设成「关键词」,分词口径会报 0%,而子串口径报 3 次——这不是 bug,是两套词典的差异,所以本页永远把子串口径排在第一位。

停用词表为什么必须内置而不是照搬。本页内置 83 条(中文 59 + 英文 24)。Google 从未公布中文停用词表,各家工具的列表都是自拟的,这就是「同文不同数」的第二个来源。示例里过滤掉的 4 个词是「不是 / 没有 / 所以 / 怎么」——它们在多字词分母里出现两次(「不是」两次、「没有」「所以」「怎么」各一次,按实测是剔除 5 个:分母 68 → 63)。过滤停用词不改变分子、只缩小分母,所以密度会升高:示例的口径④从 4.41% 升到 4.76%。很多工具不告诉用户自己做了这一步,于是同样的文本得出两个都「有道理」的结果。

单字词为什么不计。示例里单字「的」出现 2 次,占全部词 1.40%、占汉字 0.99%。单字虚词在中文里承担语法功能而非主题,SEO 密度统计惯例一律排除——所以本页默认词长下限是 2。把下限调到 1,「密度」的分母会从 68 涨到 143,密度随之腰斩,这就是「下限设 1 就不超标」的机制。

遵循的标准。分词接口由 ECMA-402(Internationalization API)定义,granularity: 'word' 的切分遵循 ICU 的 UAX #29 词边界规则加上中文词典;语言标签用 BCP 47 形式 zh-Hans。isWordLike 是 ECMA-402 里 SegmentData 的标准字段,判据是「该片段是否由字母、数字或汉字构成」。经验阈值 0.8% / 1% / 3.5% 不是任何标准的一部分,是内容营销实践里的经验值,本页把它标为「经验区间」而非「合格线」。

完整示例(数值仅作演示)

示例条件与页面默认值完全一致:正文 202 汉字、目标词「密度」、词长 2~4 字。逐项核对:

这六个数字都能在正文里互相印证:口径④的 4.41% 对应分母 68(未过滤),词频榜的 4.76% 对应分母 63(已过滤),两者之差纯粹来自停用词表。下面「分母 → 同一词密度」对照表把 63 这个分母换算成 1~5 次出现时各自的密度,能直接看出 3.5% 在这份正文里只有 2 次余量。

输入范围与对照表

下面这张表回答「同一个词,换个分母会变成多少」——这是本页最容易被忽略、也最容易造成误判的一层:

分母口径分母目标词 1 次2 次3 次4 次
① 子串 ÷ 标点分段30 段3.33%6.67%10.00%13.33%
② 子串 ÷ 汉字数202 字0.50%0.99%1.49%1.98%
③ 分词 ÷ 全部词143 词0.70%1.40%2.10%2.80%
④ 分词 ÷ 多字词68 词1.47%2.94%4.41%5.88%
⑤ 二元 ÷ bigram201 个0.50%1.00%1.49%1.99%
本页词频榜(④去停用词)63 词1.59%3.17%4.76%6.35%

最后一列读法:按本页默认口径,3.5% 的上限对应 2 次——出现 2 次就到 3.17%、3 次就到 4.76%。而按口径①,同样 3 次是 10.71%,早就越界。这就是「同一篇文章,有人说刚好、有人说爆表」的完整解释。

边界与口径精度说明

常见问题

我把目标词设成「关键词」,分词口径报 0%,是 bug 吗?

不是。本页实测 Intl.Segmenter('zh-Hans') 会把「关键词」切成 ["关键","词"]、「优化」切成 ["优","化"]——V8 内置 ICU 的中文断词词典对这类高频双字组合反而拆得更细。所以分词口径按「完整词」比对时必然是 0 次。子串口径不经过分词,仍然能数出真实次数,这也是本页把它排在第一位的原因。

密度 5% 算高吗?

先看你用的是哪个分母。同样 5 次出现,在本页 63 词的分母下是 7.94%,在 202 汉字的分母下只有 2.48%。经验区间 1%~3.5% 是相对「总词数」说的,而中文的总词数本身有五种算法。更实用的判断标准是词频榜:如果目标词排在第一位且明显甩开第二名,多半是写重复了;如果它排在第三名以下、密度也只有 1% 左右,那不是问题。

为什么停用词过滤会让密度升高?

因为分子不变、分母变小。示例里「密度」出现 3 次,多字词分母从 68 降到 63,密度就从 4.41% 升到 4.76%。停用词(「不是」「所以」「怎么」这类)承担语法功能而非主题,把它们算进分母只会稀释真实密度。关键是要知道工具做没做这一步——本页在结果里明确写出过滤前后的两个分母。

单字词(「的」「是」「了」)要不要算?

默认不算,本页词长下限是 2 字。示例里单字「的」出现 2 次,占全部词 1.40%——一个虚词就能贡献 1.4 个百分点,如果计入的话所有词的密度都会被稀释得很低,看起来「都很健康」,这正是把虚词算进去的弊病。把下限调到 1 可以看到变化,但那个数字没有参考价值。

正文里全是标点或空格会怎样?

会被明确拒绝并提示「没有可统计的词:正文里 0 个汉字、0 个可切分词」。页面不会输出 Na%、也不会静默显示 0.00%。这类输入通常是粘贴失败或选中了错误的文本范围,看到提示就回去重粘一次。

目标词要不要加引号或书名号?

不要。目标词必须是纯文本,页面对任何非空输入都按字面子串匹配。如果原文里写的是「“密度”」带引号形式,引号不参与匹配,所以能正常命中;反过来,输入目标词时若带上了引号,就永远匹配不到。

同一段文字在 Chrome 和 Firefox 上结果不同,正常吗?

正常,而且这正是本页强调「口径」的原因。分词口径的分母来自 Intl.Segmenter,而它背后是浏览器内置的 ICU 词典,不同版本收录的词条不同,压缩比会变(示例是 0.708)。子串口径和二元口径不依赖词典,跨浏览器结果一致。想要可复现的结论,就只用口径① ② ⑤,或者自己固定分母。

检测过的正文会被上传吗?

不会。全部计算在当前页面完成,只调用 String.indexOf、正则和 Intl.Segmenter,没有任何网络请求,也不写 Cookie 或 localStorage。你可以在开发者工具的 Network 面板里反复点「检测密度」,面板始终是空的——需要粘贴敏感文稿时这一点很关键。

相关工具