博客添加文章字数、代码行数和预计阅读时间功能

nZone 2023年11月5日更新于1 年前 共1849字 225行代码 预计10分钟 评论 107

这几天在研究WordPress博客系统怎么添加字数统计和阅读时间估算的功能,这两个功能可以给作者和读者提供有用的信息,作者可以根据字数统计来调整文章的长度,以满足其受众的需求,而读者可以参考阅读时间,估算需要多长时间来完整阅读一篇文章。

实现这两个功能并不难,算法和实现方式有很多种,哪一种准确才是难。闹网文章代码并不多,不过最近在研究代码,就顺便再加个代码总行数显示。

标题下方添加字数行数和阅读时间

一、文章字数统计

文章字数统计有很多种方式,之前没去深入研究,估计有很多博客的算法都比较简单,闹着玩下网最早的写法是借用底下版权声明的代码,这 count_words 是 begin 主题自带的函数,直接放到标题下方可以正常显示。

echo count_words($post->post_content);

但在开发模式下提示错误,因为这里的 $post 变量没有定义,所以在调用时报错。可以修改为 get_the_content() 内置函数,安全地获取文章内容。

echo count_words(get_the_content());

二、文章预计阅读时间

本来这篇文章就可以结束了,但想加个阅读时间,测试估算时间不太准确,发现是这字数统计不太严谨。笔者对比微信的文章编辑系统,网站统计的字数比微信的字数要多一些。

// 获取全文内容
$content = get_the_content();

// 过滤HTML标签并提取纯文本
$text = strip_tags($content);

// 使用正则表达式匹配中文字符
preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $text, $matches);
$cnContent = join('', $matches[0]);

// 计算中文字符数量
$cnCharacterCount = mb_strlen($cnContent, 'UTF-8');

// 使用正则表达式去除非字母和数字的字符,保留空格
$enContent = preg_replace("/[^A-Za-z0-9 ]/u", '', $text);

// 计算英文字符数量
$enCharacterCount = strlen($enContent);

// 计算空格数量
$spaceCount = substr_count($text, ' ');

// 方便查看具体数量,可删除
echo "中文字符数量: ${cnCharacterCount} 字符<br>";
echo "英文字符数量: ${enCharacterCount} 字符<br>";
echo "空格数量: ${spaceCount} 个空格<br>";

// 计算中英文总字数
echo "本文共 " . ($cnCharacterCount + $enCharacterCount) . " 个字。";

// 计算中文阅读时间(250个字/分钟)
$cnTime = ceil($cnCharacterCount / 250);

// 计算英文阅读时间(200个单词/分钟)
$enWords = str_word_count($enContent);
$enTime = ceil($enWords / 200);

// 总阅读时间
$readTime = $cnTime + $enTime;
echo " 预计${readTime}分钟";

三、文章代码总行数

又想加个代码行数的,一分钟看几行,不过代码不多。

1、代码行数换算为字数

看代码的速度和文章不一样,代码一般看行数,考虑拿行数去换算为字数,假设每行代码5个字:

// 获取全文内容
$content = get_the_content();

// 提取 code 和 pre 标签中的代码内容
$codeContent = preg_match_all('/<(?:code|pre)>(.*?)<\/(?:code|pre)>/s', $content, $matches);
$codeContent = $matches[1];

// 统计代码总行数
$totalLines = 0;
foreach ($codeContent as $code) {
  $lines = count(explode("\n", $code));
  $totalLines += $lines; 
}

// 假设每行代码相当于5个字
$codeCount = $totalLines * 5; 

// 提取中文字符串,按字数统计
$cnContent = preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $content, $matches);
$cnContent = join('', $matches[0]);
$cnCount = mb_strlen($cnContent);

// 提取英文单词,使用空格分割  
$enContent = preg_replace("/[^A-Za-z0-9 ]/u","", $content);
$enWords = preg_split("/\s+/",$enContent);
$enCount = count($enWords);

// 总字数统计
$wordCount = $cnCount + $enCount + $codeCount;

// 输出结果
echo " 共{$wordCount}字";
if ($codeCount > 0) {
    echo " 代码{$totalLines}行\n";
}

// 总阅读时间(250个字/分钟)
$readTime = ceil($wordCount / 250);
echo " 预计${readTime}分钟";

2、代码直接算字数

用换算也不太准确,不如还是直接算吧。代码的计算方式有点复杂,下划线连在一起的该算几个字呢?

闹网是按中英文总字数,再加代码行数,计算阅读时间则是包括代码的字数。假设代码中的字以空格分隔,这并不准确,也只是算个大概。

现在最终版是写个函数,然后直接调用。

//字数代码行统计
function count_nzonex($content) {
    // 移除链接、图片描述和图片链接
	$content = preg_replace('/<a[^>]*>.*?<\/a>|<img[^>]* alt=["\'][^"\']*["\'][^>]*>/s', ' ', $content);

    // 统计中文字符数量
    preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $content, $matches);
    $cnCount = count($matches[0]);

    // 统计英文单词数量
    preg_match_all('/\b\w+\p{N}*\b/', $content, $matches);
    $enCount = count($matches[0]);

    // 统计连续数字字符作为一个字
    preg_match_all('/\d+/', $content, $matches);
    $nuCount = count($matches[0]);

    // 统计代码行数和字数
    preg_match_all('/<code>(.*?)<\/code>/s', $content, $matches);
    $codeContent = $matches[1];
    $codeLines = 0;
    $codeWords = 0;

    foreach ($codeContent as $code) {
        $lines = count(explode("\n", $code));
        $codeLines += $lines;
        // 统计代码字数,假设代码中的字以空格分隔
        $codeWords += str_word_count(strip_tags($code));
    }

    return array(
        'cnCount' => $cnCount,
        'enCount' => $enCount,
        'nuCount' => $nuCount,
        'codeLines' => $codeLines,
        'codeWords' => $codeWords,
    );
}

function content_readTime_nzonex($content) {
    $counts = count_nzonex($content);
    $cnCount = $counts['cnCount'];
    $enCount = $counts['enCount'];
    $nuCount = $counts['nuCount'];
    $codeLines = $counts['codeLines'];
    $codeWords = $counts['codeWords'];

    // 计算总字数
    $totalWords = $cnCount + $enCount + $nuCount + $codeWords;
    $CountWords = $cnCount + $enCount + $nuCount;

    // 计算总字数的阅读时间,每分钟约250字
    $readTime = ceil($totalWords / 250);

    //$result = "总{$totalWords}字,除代码外共{$CountWords}字";
    $result = "共{$CountWords}字";

    if ($codeLines > 0) {
	//$result .= ",代码{$codeLines}行 共{$codeWords}字";
        $result .= "+代码{$codeLines}行";
    }
    $result .= " 预计阅读{$readTime}分钟";

    return $result;
}

这个写法似乎太复杂了,还可以再优化一下。

// 统计文章字数代码行
function count_words_nzonex($content) {
  // 参数验证,确保内容不为空
  if (empty($content)) {
    return [
      'cn' => 0,
      'en' => 0,
      'nu' => 0,
      'codelines' => 0,
      'codewords' => 0
    ];
  }

  // 提取代码内容
  preg_match_all('/<code>(.*?)<\/code>/si', $content, $code_matches);
  $code = $code_matches[1];
  
  // 移除HTML标签
  $content = strip_tags($content);

  // 统计中文字数  
  preg_match_all('/[\x{4e00}-\x{9fff}]/u', $content, $cn_matches);
  $cn_count = count($cn_matches[0]);

  // 统计英文字符数
  preg_match_all('/\w+/u', $content, $en_matches);  
  $en_count = count($en_matches[0]);

  // 统计数字字数
  preg_match_all('/\d+/u', $content, $nu_matches);
  $nu_count = count($nu_matches[0]);  

  // 统计代码行数、字数
  $code_lines = 0;
  $code_words = 0; // 初始化code_words
  foreach ($code as $c) {
    // 逐行统计
	$lines = count(explode("\n", $c)); // 分割行数
    $code_lines += $lines;
    $code_words += str_word_count(strip_tags($c));
  }  

  return [
    'cn' => $cn_count,
    'en' => $en_count,
    'nu' => $nu_count,
    'codelines' => $code_lines, 
    'codewords' => $code_words
  ];
}

// 计算阅读时间  
function content_readTime_nzonex($content) {
  // 统计字数
  $counts = count_words_nzonex($content);

  $cn_count = $counts['cn'];
  $en_count = $counts['en'];
  $nu_count = $counts['nu'];
  $code_lines = $counts['codelines'];
  $code_words = $counts['codewords'];
  //总字数
  $total_words = $cn_count + $en_count + $nu_count + $code_words;
  //除代码外的字数
  $text_words = $cn_count + $en_count + $nu_count;

  $readtime = ceil($total_words / 250);

  $result = "共{$text_words}字";

  if ($code_lines > 0) {
    $result .= "+{$code_lines}行代码"; 
  }

  $result .= " 预计阅读{$readtime}分钟";
  
  return $result;
}

这样可以在别处调用这个函数,如下:

echo content_readTime_nzonex(get_the_content());

就会输出结果,可以参考本文标题下方的信息。

感觉又学到了一点皮毛。

weinxin
公众号
闹着玩下网
avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: