markdown 文章字数统计的规则思考与解决方案

ziyuan 2025-10-17 阅读:15 评论:0
最近在制作 Typecho default ultra 主题,在这个主题中我加入了对文章字数统计的功能。此前我也参考了其他优秀的开发者的文章字数统计方式,我自己也优化了好几次。文章字数统计,看起来是一个很简单的小功能,为什么值得被优化好几次...
=======================================

2000T学习,音乐,视频,书籍等资源。持续更新中

=======================================

最近在制作 Typecho default ultra 主题,在这个主题中我加入了对文章字数统计的功能。此前我也参考了其他优秀的开发者的文章字数统计方式,我自己也优化了好几次。

文章字数统计,看起来是一个很简单的小功能,为什么值得被优化好几次?其实原因很简单,现存的方案统计出来的结果,与预估结果误差太大。

先看看现有的文章字数统计方案。

方案 1:源自百度搜索结果。

function count($cid) {	// 方法传入文章cid,然后根据cid从数据库中获取文章的内容
    $db = Typecho_Db::get();    $row = $db->fetchRow ($db->select ('table.contents.text')->from ('table.contents')->where ('table.contents.cid = ?', $cid)->order ('table.contents.cid', Typecho_Db::SORT_ASC)->limit (1));    $text = $row['text'];	// 自动检测原文本的编码并转换为UTF-8编码
    $text = mb_convert_encoding($text, 'UTF-8', 'auto');	// 过滤空白字符
    $text = str_replace('/( |\s|\r\n|\n|\r)+/u', '', $text);	// 使用正则替换删除所有非中文字符
    $text = preg_replace('/[^\x{4e00}-\x{9fa5}]/u', '', $text);	// 计算中文字符长度
    $count = mb_strlen($text, 'UTF-8');	// 返回统计结果
    return $count;
}

这个方案的问题在于:它只统计中文字符的数量,文章中的英文不统计?数字也不统计?按理来说,中文字符、英文、数字都要统计到字数中去的。

方案 2:源自百度搜索结果。

<?php// 方法直接传入文章的内容,输出计算结果echo mb_strlen($this->content);?>

这个方案的问题在于:mb_strlen 函数能够统计中文、日文、英文、数字等等,UTF-8 编码的中文字符计为 1 个长度,但是一个英文字母也会被计为 1 个长度。理论上来说,一个完整的单词才能计为 1 个长度。本质上,mb_strlen 函数计算的是 Unicode 字符数。

基本上所有的文章字数统计方案,都没办法很好的计算出预估结果。

对于一般情况下的字数统计,我的预估效果是这样的:

  • 1 个中文算 1 个字,如“你好”算 2 个字。

  • 1 个中文符号算 1 个字,如“你好。” 算 3 个字。中文标点符号占用的是全角字符的位置,每一个标点符号都占有等宽的空间,相当于一个汉字,因此中文符号也可以做为独立的元素被计入字数。

  • 1 个英文单词算 1 个字,如“hello world”算 2 个字,“user-name”算 1 个字,“don’t”算 1 个字。对于英文来说,字数的统计焦点在于单词的数量。

  • 英文符号不计算在内。英文符号多为半角字符,通常被用来分隔单词或短语。英文符号在字数统计中不被计算是因为它们的主要功能是语法上的,而非构成独立语义单位。

  • 1 串完整的数字算 1 个字,如“123”算 1 个字,“138 888 8899”算 3 个字。

  • 1 串完整的数字 + 英文算 1 个字,如“user123”算 1 个字,“https://www.duozai.cn/page/7.html”算 1 个字。

  • 空字符串不计算在内。

  • 其他 Unicode 如日文、韩文,正常计算字符。

对于 Typecho Markdown 格式的文章字数统计,我的预估效果是这样的:

  • Markdown 的所有标记都不能算入字数,如标题井号、分隔符横杠、列表星号横杠等。

  • Markdown 图片链接不能算入字数,图片描述算入字数。

  • Markdown 链接地址不能算入字数,链接描述算入字数。

  • Markdown 代码块中的内容算入字数,代码块标记、代码块语言标记不能算入字数。

  • Typecho Markdown 格式的文章文本开头有一个固定的 markdown 注释,这也不能算入字数。

在多次优化和调整之下,整出了个文章字数统计的方法:

/**
 * 计算文章字数
 */function postWordCount($archive) {    $db = Typecho_Db::get ();    $cid = $archive->cid;    // 获取文章内容
    $rs = $db->fetchRow($db->select ('table.contents.text')->from ('table.contents')->where ('table.contents.cid = ?', $cid)->order ('table.contents.cid', Typecho_Db::SORT_ASC)->limit (1));    $content = $rs['text'];    
    // 匹配 Markdown 标记的正则规则
    $rules = [        '/<!--markdown-->/' => '',        '/^#{1,6}\s+/m' => '',        '/(\*{1,2}|_{1,2})/' => '',        '/\[([^\]]+)\]\([^)]+\)/' => '$1',        '/!\[([^\]]*)\]\([^)]+\)/' => '$1',        '/‍```.*?\R/' => '',        '/\R‍```/' => '',        '/`/' => '',        '/^[ \t]*[-*+]\s+/m' => '',        '/^[ \t]*\d+\.\s+/m' => '',        '/^>\s*/m' => '',        '/^[-*_]{3,}\s*$/m' => '',        '/\|/' => '',        '/^[-: ]+$/' => '',
    ];    
    foreach ($rules as $pattern => $replacement) {        // 移除 Markdown 标记
        $content = preg_replace($pattern, $replacement, $content);
    }    if (empty($content)) {        return 0;
    }    // 处理空格(合并连续空格为1个,保留分隔作用)
    $content = preg_replace('/\s+/', ' ', $content);    $content = trim($content);    if ($content === '') {        return 0;
    }    // 字数计数器
    $count = 0;    
    // 按空格拆分成独立块
    $blocks = preg_split('/\s+/', $content);    foreach ($blocks as $block) {        if (empty($block)) {            // 空格不计数
            continue;
        }        // 核心正则:按规则优先级拆分内容(先拆1-2类,再拆3类,最后剩4类)
        // 匹配单个中文字符、单个中文符号、连续的英文/数字/英文符号序列、其他 Unicode
        preg_match_all('/([\x{4e00}-\x{9fa5}]|[\x{3000}-\x{303f}\x{ff00}-\x{ffef}]|[a-zA-Z0-9\!\@\#\$\%\^\&\*\(\)\-\_\+\=\[\]\{\}\|\\\;\:\'\"\,\.\<\>\/\?\`]+|.)/ux', $block, $matches);        // 按规则计数
        foreach ($matches[0] as $part) {            // 所有规则均为“单个/连续序列算1”,直接累加
            $count++;
        }
    }    // 向上取整统计大约字数
    return ceil($count / 10) * 10;
}

这个方案,基本满足了我的预估效果。


版权声明

本站名称:资源百科
本站永久网址:https://ziyuanbaike.com/
本站的文章部分内容可能来源于网络,如有侵权,请联系站长heytool@126.com进行删除处理。
本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。

分享:

扫一扫在手机阅读、分享本文

发表评论
热门文章
  • 太极v2.9.7,聚合软件最新版,25+源也非常猛了!

    太极v2.9.7,聚合软件最新版,25+源也非常猛了!
    太极(Windows)这是一个Windows桌面端的聚合软件,拥有很多功能,比如观山、听雨、修仙、抚琴、小站、览竹、宝库首先是观山,实际上就是很多美图,以前主打小姐姐美图,现在不仅有小姐姐壁纸,还有UnSplash、动态壁纸、次元岛等12+接口,现在的版本不仅支持下载,还可以一键设置成壁纸,非常方便。再来看听雨板块,其实就是音悦播放模块,早期的太极只能简单播放,但是现在的太极不仅拥有7+接口随便用,而且还支持添加歌单和播放本地音悦,并且还支持歌词显示,也支持文件下载,可以说非...
  • 开源阅读App,附最新收录9000+的书源仓库!

    开源阅读App,附最新收录9000+的书源仓库!
    昨天看到开源阅读的官方频道发消息再一次推荐了一个阅读爱好者做的书源网站,今天给大家推荐分享一下。阅读(安卓)趣哥相信正在看文章的小伙伴绝大多数都知道阅读这个App吧,这是一个支持自定义书源的电子书阅读软件。但是阅读的大版本已经停更很久了,现在还在小版本更新,基本只有一些小修复,大家可以在下面分享的第一个书源仓库网站上下载它的最新版。不过就算阅读App停更,现在依然有大佬维护规则,而今天分享的两个书源网站就是收集了众多书源规则的书源仓库。Yiove书源仓库第一个是Yiove书源...
  • 资源百科:古典文学必读:越看越上瘾的古代争斗小说(套装共30册)

    资源百科:古典文学必读:越看越上瘾的古代争斗小说(套装共30册)
    古典文学必读:越看越上瘾的古代争斗小说(套装共30册).jpg 古典文学必读:越看越上瘾的古代争斗小说(套装共30册).mobi 古典文学必读:越看越上瘾的古代争斗小说(套装共30册).epub。古典文学必读:越看越上瘾的古代争斗小说(套装共30册)链接:https://pan.quark.cn/s/2b38240b29ea...
  • 2000T夸克盘学习资源

    2000T夸克盘学习资源
    2000T资源汇总,每天更新https://www.yunpan.com/surl_y9Q7sVRzXt6 (提取码:bfa4)实时更新链接https://docs.qq.com/sheet/DVGF1cmhrdWd0b2Fw?tab=BB08J2 知乎盐选付费知识合集1200+PDF文档资源https://pan.quark.cn/s/5e21e6503e7d精整2024年1月国内外无损音乐专题【202.5GB】https://pan.quark.cn/s/f2a2ea58...
  • 理想树《2025版初中必刷题 (全科上册) 》

    理想树《2025版初中必刷题 (全科上册) 》
    资源信息初中全科上册必刷题汇总,新考法、新素材,基础与重点并重,轻松备战中考。资源目录├── 初中必刷题-7上-道法人教版.pdf 263.83M ├── 初中必刷题-7上-道法人教版狂K重点.pdf 166.73M ├── 初中必刷题-7上-道法人教版批注式详答与详析.pdf 184.32M ├── 初中必刷题-7上-地理人教版.pdf 272.09M ├── 初中必刷题-7上...