可读性

《夏洛的网》封面

要解决的问题

根据 Scholastic 的资料,E. B. White 的 Charlotte’s Web 大约适合二到四年级阅读,而 Lois Lowry 的 The Giver 大约适合八到十二年级阅读。不过,一本书处于某个阅读年级水平,究竟是什么意思呢?

很多时候,人类专家可能会读完一本书,然后判断它最适合哪个年级(也就是学校中的哪一年级)。但算法也很可能做到这一点!

请在名为 readability 的文件夹中创建 readability.c 文件,并实现一个程序,计算理解某段文本大约需要的年级水平。程序应输出 “Grade X”,其中 “X” 是计算出的年级,四舍五入到最接近的整数。如果年级为 16 或更高(相当于或高于本科高年级阅读水平),程序应输出 “Grade 16+”,而不是精确数字。如果年级低于 1,程序应输出 “Before Grade 1”。

演示

背景

那么,较高阅读水平的文本通常有什么特征呢?较长的单词很可能与较高阅读水平相关。同样,较长的句子也很可能与较高阅读水平相关。

多年来,人们开发了许多“可读性测试”,用公式计算一段文本的阅读年级。其中一种可读性测试是 Coleman-Liau 指数。Coleman-Liau 指数用于输出理解某段文本所需的(美国)年级水平。公式如下:

index = 0.0588 * L - 0.296 * S - 15.8

其中 L 表示文本中每 100 个单词的平均字母数,S 表示文本中每 100 个单词的平均句子数。

建议

先写一些你确定能编译的代码
#include <ctype.h>
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

int main(void)
{

}

注意,你现在已经包含了一些头文件,这些头文件会让你能使用一些可能帮助你解决本题的函数。

在继续写更多代码前,先写一些伪代码

如果你还不确定如何解决这个问题,可以先把它拆成几个你大概能解决的小问题。例如,这个问题其实只包含少数几个步骤:

  1. 提示用户输入一段文本
  2. 统计文本中的字母数、单词数和句子数
  3. 计算 Coleman-Liau 指数
  4. 输出年级水平

我们可以把这些步骤写成注释形式的伪代码,提醒自己要完成什么:

#include <ctype.h>
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    // Prompt the user for some text

    // Count the number of letters, words, and sentences in the text

    // Compute the Coleman-Liau index

    // Print the grade level
}
把伪代码转换成代码

首先,思考如何提示用户输入一段文本。回忆一下,CS50 库中的 get_string 函数可以提示用户输入字符串。

#include <ctype.h>
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    // Prompt the user for some text
    string text = get_string("Text: ");

    // Count the number of letters, words, and sentences in the text

    // Compute the Coleman-Liau index

    // Print the grade level
}

现在你已经从用户那里收集了输入,可以开始分析它。首先,尝试统计文本中的字母数。这里的字母指大写或小写英文字母,不包括标点、数字或其他符号。

一种做法是创建一个名为 count_letters 的函数,接受字符串 text 作为输入,并以 int 形式返回该文本中的字母数。

int count_letters(string text)
{
    // Return the number of letters in text
}

你需要自己编写代码来统计文本中的字母数。不过,已经有人写好了用于判断字符是否为字母的函数。这正好是使用 CS50 manual 的好机会;它汇集了 C 标准库中常用函数的说明。

你可以像下面这样,把 count_letters 整合进已经写好的代码。

#include <ctype.h>
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

int count_letters(string text);

int main(void)
{
    // Prompt the user for some text
    string text = get_string("Text: ");

    // Count the number of letters, words, and sentences in the text
    int letters = count_letters(text);

    // Compute the Coleman-Liau index

    // Print the grade level
}

int count_letters(string text)
{
    // Return the number of letters in text
}

接下来,编写一个统计单词数的函数。

int count_words(string text)
{
    // Return the number of words in text
}

在本题中,我们把由空格分隔的任意字符序列视为一个单词(因此像 “sister-in-law” 这样的连字符单词应算作一个单词,而不是三个)。你可以假设一个句子:

  • 至少包含一个单词;
  • 不会以空格开头或结尾;并且
  • 不会连续出现多个空格。

在这些假设下,你也许能找出单词数量和空格数量之间的关系。当然,也欢迎你尝试写出能够处理单词之间多个空格,甚至完全没有单词的解法!

现在可以像下面这样,把 count_words 整合进你的程序:

#include <ctype.h>
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

int count_letters(string text);
int count_words(string text);

int main(void)
{
    // Prompt the user for some text
    string text = get_string("Text: ");

    // Count the number of letters, words, and sentences in the text
    int letters = count_letters(text);
    int words = count_words(text);

    // Compute the Coleman-Liau index

    // Print the grade level
}

int count_letters(string text)
{
    // Return the number of letters in text
}

int count_words(string text)
{
    // Return the number of words in text
}

最后,编写一个统计句子数的函数。你可以把任何以 .!? 结尾的字符序列视为一个句子。

int count_sentences(string text)
{
    // Return the number of sentences in text
}

你可以像下面这样,把 count_sentences 整合进你的程序:

#include <ctype.h>
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

int count_letters(string text);
int count_words(string text);
int count_sentences(string text);

int main(void)
{
    // Prompt the user for some text
    string text = get_string("Text: ");

    // Count the number of letters, words, and sentences in the text
    int letters = count_letters(text);
    int words = count_words(text);
    int sentences = count_sentences(text);

    // Compute the Coleman-Liau index

    // Print the grade level
}

int count_letters(string text)
{
    // Return the number of letters in text
}

int count_words(string text)
{
    // Return the number of words in text
}

int count_sentences(string text)
{
    // Return the number of sentences in text
}

最后,计算 Coleman-Liau 指数,并输出得到的年级水平。

  • 记住,Coleman-Liau 指数使用 index = 0.0588 * L - 0.296 * S - 15.8 计算。
  • L 是文本中每 100 个单词的平均字母数:也就是字母数除以单词数,再乘以 100。
  • S 是文本中每 100 个单词的平均句子数:也就是句子数除以单词数,再乘以 100。
  • 你需要把结果四舍五入到最接近的整数;根据 manual.cs50.ioround 声明在 math.h 中。
  • 记住,在 C 中对 int 类型的值做除法,结果也会是 int,任何余数(也就是小数点后的数字)都会被丢弃。换句话说,结果会被“截断”。在计算 LS 时,你可能需要先把一个或多个值转换为 float

如果得到的指数为 16 或更高(相当于大学高年级或更高的阅读水平),程序应输出 “Grade 16+”,而不是输出精确的指数。如果指数小于 1,程序应输出 “Before Grade 1”。

讲解视频

如何测试

请用以下文本运行你的程序,确保输出指定的年级水平。复制时请只复制文本本身,不要包含额外空格。

  • One fish. Two fish. Red fish. Blue fish. (Before Grade 1)
  • Would you like them here or there? I would not like them here or there. I would not like them anywhere. (Grade 2)
  • Congratulations! Today is your day. You're off to Great Places! You're off and away! (Grade 3)
  • Harry Potter was a highly unusual boy in many ways. For one thing, he hated the summer holidays more than any other time of year. For another, he really wanted to do his homework, but was forced to do it in secret, in the dead of the night. And he also happened to be a wizard. (Grade 5)
  • In my younger and more vulnerable years my father gave me some advice that I've been turning over in my mind ever since. (Grade 7)
  • Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, "and what is the use of a book," thought Alice "without pictures or conversation?" (Grade 8)
  • When he was nearly thirteen, my brother Jem got his arm badly broken at the elbow. When it healed, and Jem's fears of never being able to play football were assuaged, he was seldom self-conscious about his injury. His left arm was somewhat shorter than his right; when he stood or walked, the back of his hand was at right angles to his body, his thumb parallel to his thigh. (Grade 8)
  • There are more things in Heaven and Earth, Horatio, than are dreamt of in your philosophy. (Grade 9)
  • It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him. (Grade 10)
  • 一份 large class of computational problems involve the determination of properties of graphs, digraphs, integers, arrays of integers, finite families of finite sets, boolean formulas and elements of other countable domains. (Grade 16+)

正确性

check50 cs50/problems/2026/x/readability

代码风格

style50 readability.c

如何提交

在终端中执行以下命令提交你的作业,并按提示完成操作。

submit50 cs50/problems/2026/x/readability