SMOG公式与JavaScript实现:文本可读性检测的实用指南

发布时间:2026/10/6 3:58:12
SMOG公式与JavaScript实现:文本可读性检测的实用指南 简介1969年提出的“SMOG公式”即简单度量语言混杂度的公式被封装为一份现代网页脚本工具库用于检测文本阅读难易程度。它通过统计句子总数与多音节词总数计算出文本对应的年级阅读水平特别适合前端开发者、技术文档写作者和语言教育研究者使用。工具库仅支持ESM模块化标准需要Node 12以上的运行环境核心方法传入句子数与多音节词数两个参数即可返回最终的可读性分数。压缩包共12个文件包含JavaScript源代码、JSON配置文件、YAML工作流、Markdown说明文档及License授权文件等类型整体仅6KB十分轻量便携。目前已有三百六十八人学习或下载若想理解可读性算法实现或快速集成该公式这里提供完整源码、测试用例与项目配置可直接参考学习。1. SMOG 公式是什么1969 年的“阅读难度计算器”到现在还在用如果你做内容运营、文档体系或者教育产品大概率听过 Flesch Reading Ease但 SMOGSimple Measure of Gobbledygook这个 1969 年由 G. Harry McLaughlin 提出的指标国内讲得不多。它的核心思路极其简单一段英文里“多音节词”越多读起来就越费劲而这个费劲的程度可以直接换算成“读者需要受多少年教育才能读懂”。标题里的 smog-formula就是把这条 1969 年的旧公式封装成现代编程接口的典型实现——你喂它一段英文文本它返回一个年级数值比如 8.7意味着这段文字大致对应美国初中二年级的阅读水平。这个指标最有意思的地方在于它没有去分析语法、句式、从句嵌套这些复杂特征抓住“多音节词数量”这一个信号就能得到和人工判断高度一致的结果。对今天做内容质量检测、文案改写、术语治理、甚至儿童读物的难度分级SMOG 仍然是一个低成本高性价比的起点。2. 从公式到算法SMOG 的数学定义和计算流程2.1 英文里“难读”到底指什么多音节词是核心信号要理解 SMOG先要接受一个反直觉的事实在英文可读性研究里“难懂”不主要由句子长度决定而是由“词的长度”决定。一个句子哪怕很短只要塞进几个三音节以上的词——“utilization”“implementation”“methodology”——读者就得停下来在脑子里拆音节。McLaughlin 在 1969 年做大量样本统计后发现文本里多音节词的比例和读者实际需要的受教育年限之间存在强相关于是他干脆把“每 30 句话里有多少个多音节词”当作唯一的自变量。这里的“多音节”指的是三个及以上音节的英文单词。为什么是三因为英语母语者的日常词汇绝大多数是单音节和双音节一旦出现三音节词往往就意味着来自拉丁语或希腊语的长词根语义也更抽象。这个判断相当粗暴但统计上是站得住的。2.2 30 句采样窗口为什么不是全篇也不是 10 句SMOG 原文规定了它的计算窗口不是全文而是“连续 30 个句子”。为什么是 30McLaughlin 做过实验10 句的样本方差太大不同段落之间分数波动剧烈50 句又太长手工数词根不现实。30 句是一个在统计稳定性和人力成本之间的折中方案。实际落地的时候绝大多数现代实现并不严格只取 30 句而是把整篇文本的句子全部纳入统计再按句子数量做归一化。原因很简单工程上没必要为了“恰好 30 句”去截断文本整篇算反而更稳。但如果你要严格复现 1969 年的原始结论就必须按 30 句窗口来。我个人做内容质量检测时一般取全文同时记录总句子数——如果文本不足 30 句会将结果标记为“低置信度”。2.3 数学公式与分级对照分数怎么解读SMOG 的原始公式看着有点唬人其实拆开就两个部分。首先是统计量选 30 句数出其中所有“三个及以上音节”的词数记作 M。然后用下面这个换算[ \text{SMOG Grade} 3 \sqrt{M} ]你没看错1969 年的原版就是“3 加上 M 的平方根”。这个公式凭什么成立McLaughlin 的回归分析显示多音节词数量 M 和年级水平的平方根之间近似线性所以他直接把“开方再加 3”作为换算基准。到了 1987 年他又在后续论文里给了个更精细的修正版[ \text{SMOG Grade} 1.0430 \times \sqrt{M} 3.1291 ]这个版本比“3 根号 M”更贴身两者在高分段15 以上差距会拉大到近 1 个年级所以在做教育产品时必须用 1987 版本。下面的对照表能帮你快速判断分数含义SMOG 分数大致教育水平典型文本示例7–8初中一年级大众新闻、畅销小说9–11高中阶段科普文章、教科书章节12–14大学低年级学术论文、技术白皮书15研究生阶段法律文书、医学论文、复杂技术规范2.4 SMOG 与 Flesch、Flesch-Kincaid 的几个关键差异做文本可读性检测时SMOG 常被拿来和 Flesch-Kincaid 对比。Flesch-Kincaid 的公式是平均句长单词数/句子数加上每 100 个词里音节数的加权组合最后映射到年级水平。两者最大的差别在于Flesch-Kincaid 把句子长度放在第一位音节数量第二位SMOG 只关心多音节词句子长度只影响“采样窗口”而不直接进公式。这个差异带来两个实际后果。第一SMOG 对“短句但用词抽象”的文本更敏感——比如“The utilization of this methodology is essential”这种句子Flesch-Kincaid 因为句子短会给它一个不错的分数SMOG 却直接把它钉在高难度区。第二SMOG 的分数普遍比 Flesch-Kincaid 高 2 到 4 个年级因为它衡量的不是“轻松阅读”的阈值而是“完全理解”所需的水平。所以如果你在做内容分级通常以 SMOG 为上限标准以 Flesch-Kincaid 为下限参考。3. 用 JavaScript 实现 smog-formula从句子切分到分数输出3.1 选型理由为什么用 JavaScript 实现而不是 Python标题里的包是 smog-formula一个 npm 生态的模块所以我优先讲 JavaScript 实现。它的优势很直接前端可以在浏览器里实时测文案Node.js 后端可以把它做成内容平台的自动化检测服务不用额外维护 Python 环境。而且这个包的核心逻辑只有两个部分——句子切分和多音节词计数——用纯 JavaScript 写出来不超过 80 行你能完全掌控它的行为方便在特殊领域比如医学文本、法律文本做定制。3.2 实现步骤一句子切分SMOG 的第一个陷阱在“句子”的定义上。正则表达式/[.!?]/看着够用但一遇到Dr.、e.g.、U.S.就会切错。一个更稳妥的方式是先做缩写保护再做终止符切分。// sentenceSplitter.js const ABBREVIATIONS new Set([ dr, mr, mrs, ms, st, jr, sr, etc, e.g, i.e, vs, jan, feb, mar, apr, jun, jul, aug, sep, oct, nov, dec ]); function splitSentences(text) { // 步骤1将缩写中的句点替换为占位符 const protected text.replace(/\b([A-Za-z]{1,3})\./g, (match, word) { return ABBREVIATIONS.has(word.toLowerCase()) ? match.replace(., \u0000) : match; }); // 步骤2按终止符切分 const rawSentences protected.match(/[^.!?][.!?]/g) || []; // 步骤3恢复占位符为句点 return rawSentences.map(s s.replace(/\u0000/g, .).trim()).filter(s s.length 0); }这段代码的关键在第 3 行到第 6 行的ABBREVIATIONS集合它是一个静态白名单把 Dr.、Mr. 这种常见缩写先“标记保护”起来不让它们作为句子边界参与切分。第 8 行用\b([A-Za-z]{1,3})\.这个正则去匹配“1 到 3 个字母加一个句点”的模式如果命中白名单就把句点替换成不可见字符\u0000。第 12 行再按[.!?]切分第 15 行恢复句点。这样做的好处是缩写词本身是有限的白名单维护成本极低但能消除 90% 以上的句子边界误判。3.3 实现步骤二多音节词判定器多音节判定是整个 SMOG 实现里最容易翻车的地方。理想情况下应该用一个完整的英语音节词典来查每个词的音节数但这在 JavaScript 包体积面前不现实。常见的做法是用“元音组计数”近似连续的元音字母算一个音节然后再加上一些修正规则。// syllableCounter.js function countSyllables(word) { const lower word.toLowerCase(); // 去除词尾的静默 e不发音的 e let cleaned lower.replace(/(?:[^laeiouy]|ed|es)e$/, ); // 统计元音组数量 const vowelGroups cleaned.match(/[aeiouy]{1,3}/g); let count vowelGroups ? vowelGroups.length : 1; // 修正单词末尾的 e 不发音需要减掉 if (lower.endsWith(e) !lower.endsWith(le)) { count Math.max(1, count - 1); } return count; } function isPolysyllabic(word) { // 忽略纯数字、URL、特殊字符开头的词 if (/^[0-9#]/.test(word) || word.includes(/) || word.includes(://)) return false; return countSyllables(word) 3; }这段代码的逻辑分四层。第 4 行的正则是处理“静默 e”——英语里make、toke这类词末尾的 e 不发音如果直接数元音组会多算一个音节但le结尾如table的 e 反而参与发音所以第 11 行用Math.max(1, count - 1)做兜底保证最小音节数为 1。第 6 行用[aeiouy]{1,3}匹配连续的元音组——之所以限制最长 3 个是因为英语里超过 3 个连续元音的情况极少可以近似视为多个音节比如beautiful里的eau实际是两个音节。第 16 行的isPolysyllabic负责过滤噪音——URL、代码片段、数字串不应计入多音节词。这套规则的准确率大约在 90% 左右对常规文本文档足够如果你是做医学或法律垂直领域建议在这基础上替换成专用词表。3.4 实现步骤三在样本窗口上输出 SMOG 分数有了句子切分和多音节判定SMOG 的计算就只剩一个线性流程切分句子、遍历句子里的单词、统计多音节词数、套公式。// smog.js const { splitSentences } require(./sentenceSplitter); const { isPolysyllabic } require(./syllableCounter); function smog(text, { windowSize 30, version 1987 } {}) { const sentences splitSentences(text); // 取前 windowSize 句作为采样窗口不足则全量 const sample sentences.slice(0, windowSize); // 统计多音节词的数量 let polysyllabicCount 0; for (const sentence of sample) { const words sentence.match(/[A-Za-z](?:[-][A-Za-z])*/g) || []; polysyllabicCount words.filter(isPolysyllabic).length; } // 根据版本选择换算公式 if (version 1969) { return Math.round((3 Math.sqrt(polysyllabicCount)) * 10) / 10; } return Math.round((1.0430 * Math.sqrt(polysyllabicCount) 3.1291) * 10) / 10; } module.exports { smog };第 5 行的windowSize参数值得单独说默认值 30 是为了严格对齐麦克劳克林原始论文但如果你的文本本身只有 12 句直接取 12 句作为样本依然能算出分数只是置信度要降级——我通常会在返回值里附一个confidence字段句子数少于 15 时标记为low。第 10 行用[A-Za-z](?:[-][A-Za-z])*来切词而不是直接split(/\s/)是为了把self-learning、state-of-the-art这种连字符复合词当作一个整体处理——它们的音节需要合并计算拆开会让多音节判定失真。3.5 在 Node.js 里调用 smog-formula 的最少用法如果你不想从零实现直接用 npm 生态的现成包是最快的。npm install smog-formula// demo.js const smog require(smog-formula); const sampleText The utilization of this methodology has been widely implemented in various institutions. Quantitative analysis reveals significant discrepancies between the theoretical framework and its practical application. Nevertheless, the fundamental implications remain ambiguous without further investigation. ; const score smog(sampleText); console.log(score); // 大约 12 到 14 之间第一行npm install smog-formula拉下依赖后模块会在内部帮你完成句子切分、音节计数和公式换算。但注意现成包的判定规则是通用的不会针对你的垂直领域做调优。如果是新闻类内容直接用没问题如果是医学或法律文本建议把包源码里的音节计数器替换成专业词表或者至少跑一批你所在领域的样本文档做校准。4. 避坑指南SMOG 公式常见翻车现场与排查4.1 句子边界的“缩写陷阱”导致多音节词统计失真现象一段包含大量英文缩写如 “Dr. Smith is an expert.”的文档SMOG 分数异常偏高。3 个句子被活生生切成了 4 个多音节词被重复计数或错误分散。原因简单的正则切分把Dr.、i.e.里的句点当成了句尾导致原本一句话被拆成两段。虽然样本窗口句子数变多了但多音节词的计数也变多了平方根映射之后分数被放大。越是专业文档缩写越密集这个偏差越严重。解决启动前先跑一遍缩写白名单的单元测试。准备 10 个包含Dr.、e.g.、U.S.、Ph.D.的句子断言切分结果必须是一句。常见做法是像我在 3.2 节写的那样用占位符替换保护缩写句点如果使用现成包先确认它内部是否做了这一步——很多轻量包只做正则切分这个坑只能自己填。4.2 多音节判定的“元音组近似”把技术词数错现象文档里全是API、GUI、SQL、BIOS这种缩写词SMOG 分数飙到 15但实际读起来并不难。反过来automated、database这类技术词被计为双音节导致分数虚低。原因音节计数算法把连续元音合并API的三个字母 A-P-I 被当成“三个元音组”计 3 音节真实读音是 A-P-I 四个音节GUI被当成一个音节真实读音 G-U-I 三个音节。缩写词的音节规则和常规单词完全不同通用算法在这里完全失效。解决在isPolysyllabic函数前加一道过滤纯大写的 2 到 5 位字母组合视为缩写词直接排除。技术词表的维护是长期工程——我一般在初始化字典时把常见 IT 词根补进去比如auto算 2 音节、database算 3 音节用覆盖的方式修正算法误判。如果你处理的领域很集中比如只做云计算文档固化一个 100 词左右的领域音节表判定的准确率能拉回到 95% 以上。4.3 文本不足 30 句时分数像过山车现象拿一篇 8 句的产品简介去测SMOG 分数 10.2加了两句简单描述后再测变成了 8.9。文本越长越稳定文本越短越飘。原因SMOG 的原始采样窗口是 30 句。文本不足 30 句时多音节词的绝对数量少开方运算对手动加减一两个词都会产生明显波动。这是统计样本不足导致的方差问题不是你写错了代码。解决不足 30 句的文本要么改为对全量句子做归一化总多音节词数除以总句子数再乘 30 映射回原公式要么直接降低结果的置信度展示。不要追求“精确分数”短文本用区间表达——“大约 8 到 10 年级水平”比“9.0”有意义得多。4.4 中文文本硬套 SMOG 公式输出完全失真现象把一段中文扔进 npm 包输出一个看似合理的年级数但这数字毫无意义。中文没有空格分词、没有音节概念英文的多音节判定逻辑完全不适用。原因SMOG 的底层统计对象是“英文多音节词的频率”中文文本的汉字本身没有音节数的概念。有些包会默认把中文字符当作“单音节词”处理结果整篇文本的分数被压缩在 4 到 6 之间完全丧失区分度。解决中文可读性建议换用“汉字笔画数 句子长度 关联词密度”的组合指标。如果你必须用 SMOG 做中英混合文档先做语言识别只对英文片段计算中文片段用长度加权独立评估。硬套公式不是“玄学”是数学上根本不成立。5. 把分数变成行动数值落地时的一些小技巧拿到 SMOG 分数之后怎么把它变成业务决策是另一道坎。我给内容团队做质检时常用一个简单规则对外宣传文案的 SMOG 分数不超过 8产品帮助中心的技术文档可以到 10API 参考手册不做限制但也别超过 15——超过 15 意味着新用户基本靠猜。这条标准配合人工抽检比凭感觉改文案靠谱得多。另一个实用技巧是用“差分”而不是“绝对值”做考核。SMOG 分数受词汇选择影响很大不同领域的基线完全不同比如金融文档天然就比生活类内容高 3 到 4 分。相比设定一个硬性阈值更重要的是监控同一份文档迭代前后的分数变化——改版后如果分数涨了 2 个年级就得检查是不是引入太多术语却没有加解释。要验证你自己的实现是否准确找三篇难度明确的基准文本一篇儿童读物SMOG 期望值约 4–6、一篇《纽约时报》社论约 8–9、一篇医学论文摘要约 14–16跑完之后看输出是否落在区间内误差超过 2 就回去检查音节计数逻辑。这套基准我每次重构代码都会先拿出来跑一遍——血泪经验告诉我算法看着对不等于数字对。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询