cs50 pset 2 – 可读性

huangapple go评论59阅读模式
英文:

cs50 pset 2 - readability

问题

I'm providing the translation for your code:

我正在尝试打印出年级级别;但每次我使用 check50 检查时,都会出现以下错误:

':( 处理单个句子内的标点符号
    期望 "Grade 9\n",而不是 "There are more...\n"

唯一正确处理的年级级别是 1 年级前的阅读水平

这是我的代码:

{
    //提示用户输入文本
    string text = get_string("文本:");
    {
        printf("%s\n", text);
    }

    int count_letters(string letters);
    // 计算字母数
    int letters = 0;
    int n = 0;
    while (text[n])
    {
        if (isalpha(text[n]) != '\0')
        {
            letters++;
        }
        n++;
    } //打印字母数
    printf("%i 个字母\n", letters);
    //计算单词数
    int count_words(string words);
    int words = 0;
    int x = 0;
    while (text[x])
    {
        if ((text[x]) == ' ')
        {
            words++;
        }
        x++;
    } //打印单词数
    printf("%i 个单词\n", words);
    // 计算句子数
    int count_sentences(string sentences);
    int sentences = 0;
    int s = 0;
    while (text
展开收缩
)
{ if (ispunct(text
展开收缩
))
{ sentences++; } s++; } //打印句子数 printf("%i 个句子\n", sentences); //公式 = 索引 = 0.0588 * L(每 100 个单词的字母数)- 0.296 * S(每 100 个单词的句子数)- 15.8 float L = ((float)letters / words) * 100; float S = ((float)sentences / words) * 100; int grade = round(0.0588 * L) - (0.296 * S) - 15.8; if (grade < 1) { printf("1 年级前\n"); } else if (grade > 16) { printf("16+\n"); } else { printf("年级 %i\n", grade); } }

请注意,我已将您的代码翻译成中文。

英文:

im trying to print the grade level; however, each time i check50 it comes up with this:

':( handles punctuation within a single sentence
expected "Grade 9\n", not "There are more..."'

the only grade level it is properly handling is reading level before grade 1

here is my code:

{
//prompt user for text
string text = get_string(&quot;Text: &quot;);
{
printf(&quot;%s\n&quot;, text);
}
int count_letters(string letters);
// count letters
int letters = 0;
int n = 0;
while (text[n])
{
if (isalpha(text[n]) != &#39;\0&#39;)
{
letters++;
}
n++;
} //print number of letters
printf(&quot;%i letters\n&quot;, letters);
//count words
int count_words(string words);
int words = 0;
int x = 0;
while (text[x])
{
if ((text[x]) == &#39; &#39;)
{
words++;
}
x++;
} //print number of words
printf(&quot;%i words\n&quot;, words);
// count sentences
int count_sentences(string sentences);
int sentences = 0;
int s = 0;
while (text
展开收缩
) { if (ispunct(text
展开收缩
)) { sentences++; } s++; } //print number of sentences printf(&quot;%i sentences\n&quot;, sentences); //formula = index = 0.0588 * L(letters per 100 words) - 0.296 * S(sentences per 100 words) - 15.8 float L = ((float)letters / words) * 100; float S = ((float)sentences / words) * 100; int grade = round(0.0588 * L) - (0.296 * S) - 15.8; if (grade &lt; 1) { printf(&quot;Before Grade 1\n&quot;); } else if (grade &gt; 16) { printf(&quot;Grade 16+\n&quot;); } else { printf(&quot;Grade %i\n&quot;, grade); } }

答案1

得分: 0

以下是您要翻译的部分:

"Continuing from my comment, of your 3-loops (characters, words, and sentences), both words and sentences are wrong and will not produce the right counts. Why?

For words, you consider every &#39; &#39; to indicate a new word. However, if you have leading spaces, or 2 (or more) spaces between sentences, or trailing spaces, your word count will be incorrect.

For sentences, you use the test if (ispunct(text

展开收缩
)) to mark the end of each sentence. This too is incorrect because ispunct() will test true for:

> checks for any printable character which is not a space or an
> alphanumeric character.

(see: man 3 isalpha)

That means for every &#39; or &#39;;&#39; or &#39;&quot;&#39;, you increment your sentence count ending up with an incorrect answer. This is shown in the very first set of examples in the CS50 Readability (2023) problem statement, e.g. for Grade 3 they example is:

> Congratulations! Today is your day. You're off to Great Places! You're
> off and away!

Your code considers &quot;Today is your day. You&quot;, &quot;re off to Great Places&quot; &quot;You&quot; and &quot;re off and away&quot; to all be separate sentences.

Instead, as the instructions state, you should only consider &#39;.&#39;, &#39;?&#39; and &#39;!&#39; to mark end-of-sentence. A simple if checking all three conditions is all you need, e.g.

  if (text
展开收缩
== &#39;.&#39; || text
展开收缩
== &#39;?&#39; || text
展开收缩
== &#39;!&#39;) {
...

Use a single-loop and state-variables instead of multiple loops

As mentioned in the comments, while you can loop over the same text three-times, this is horribly inefficient for longer text. All you need is a single loop and (1) a variable to keep track of whether you are in a word, and another variable to keep track of whether you are in a sentence. A simple int will do, set to 1 (or any non-zero value) if you are in a word/sentence and then set to 0 if you are before, between or after a word or sentence.

Say you use inword to track if you are in a word reading characters and insent to track if you are in a sentence reading words/characters. As you loop continually over your text you have only four main conditions to check, e.g."

如果您需要进一步的翻译或有其他问题,请随时提出。

英文:

Continuing from my comment, of your 3-loops (characters, words, and sentences), both words and sentences are wrong and will not produce the right counts. Why?

For words, you consider every &#39; &#39; to indicate a new word. However, if you have leading spaces, or 2 (or more) spaces between sentences, or trailing spaces, your word count will be incorrect.

For sentences, you use the test if (ispunct(text

展开收缩
)) to mark the end of each sentence. This too is incorrect because ispunct() will test true for:

> checks for any printable character which is not a space or an
> alphanumeric character.

(see: man 3 isalpha)

That means for every &#39; or &#39;;&#39; or &#39;&quot;&#39;, you increment your sentence count ending up with an incorrect answer. This is shown in the very first set of examples in the CS50 Readability (2023) problem statement, e.g. for Grade 3 they example is:

> Congratulations! Today is your day. You're off to Great Places! You're
> off and away!

Your code considers &quot;Today is your day. You&quot;, &quot;re off to Great Places&quot; &quot;You&quot; and &quot;re off and away&quot; to all be separate sentences.

Instead, as the instructions state, you should only consider &#39;.&#39;, &#39;?&#39; and &#39;!&#39; to mark end-of-sentence. A simple if checking all three conditions is all you need, e.g.

  if (text
展开收缩
== &#39;.&#39; || text
展开收缩
== &#39;?&#39; || text
展开收缩
== &#39;!&#39;) {
...

Use a single-loop and state-variables instead of multiple loops

As mentioned in the comments, while you can loop over the same text three-times, this is horribly inefficient for longer text. All you need is a single loop and (1) a variable to keep track of whether you are in a word, and another variable to keep track of whether you are in a sentence. A simple int will do, set to 1 (or any non-zero value) if you are in a word/sentence and then set to 0 if you are before, between or after a word or sentence.

Say you use inword to track if you are in a word reading characters and insent to track if you are in a sentence reading words/characters. As you loop continually over your text you have only four main conditions to check, e.g.

  1. if (isspace (str[i])) { to check if you need to increment your word count. Within this condition, you simply check if (inword) { to know if you should increment your word count;
  2. else if (str[i] == &#39;.&#39; || str[i] == &#39;?&#39; || str[i] == &#39;!&#39;) { to check for an end-of-sentence condition, and then you check if (insent) { to know if you should increment your sentence count;
  3. else if (!str[i]) { to check your end-of-string and break the loop (equivalent to if (str[i] == &#39;\0&#39;) and plain old if (str[i] == 0)
  4. lastly, else if (isalpha (str[i])) { to know if you should increment your character count and set your state variables inword = insent = 1; (when you read an alpha character, you know you are in both a word and sentence reading characters)

This way, you have a single loop that avoids looping back over the same text multiple times. If you translate that into code and work through the logic, you can end up with something similar to:

#include &lt;cs50.h&gt;
#include &lt;stdio.h&gt;
#include &lt;ctype.h&gt;

/* single function to capture chars, words and sentences in a
 * single interation through the string passed as a parameter
 * to the function and compute the chars per 100 words and sentences
 * per 100 words and compute the Coleman-Liau index. Returns the
 * rounded Coleman-Liau index as an integer value.
 */
int coleman_liau_index (const char *str)
{
  int inword = 0,             /* flag in-word (1) or before/between words (0) */
      insent = 0,             /* flag in-sentence (1) or before/between (0) */
      nchars = 0,             /* total number of chars */
      nwords = 0,             /* total number of words */
      nsents = 0;             /* total number of sentences */
  double  l = 0.,             /* avg no. of letters per 100 words */
          s = 0.,             /* avg no. of sentences per 100 words */
          index = 0;          /* Coleman-Liau index */

  for (int i = 0;; i++) {     /* loop continually until out of chars */
    if (isspace (str[i])) {   /* if chars is whitespace */
      if (inword) {           /* if currently inword */
        nwords += 1;          /* increment no. of words */
        inword = 0;           /* set word flag 0 */
      }
    } /* if end-of-sentence character */
    else if (str[i] == &#39;.&#39; || str[i] == &#39;?&#39; || str[i] == &#39;!&#39;) {
      if (insent) {           /* if currently insent */
        nsents += 1;          /* increment no. of sentences */
        insent = 0;           /* set sentence flag 0 */
        /* end of sentence is also end of word, (catches end.Start case)
         * (optional for all given example input -- can you figure out why?)
         */
        nwords += 1;          /* increment no. of words */
        inword = 0;           /* set word flag 0 */
      }
    }
    else if (!str[i]) {       /* if end-of-string (null-char) reached */
      if (inword) {           /* if currently inword */
        nwords += 1;          /* increment no. of words */
      }
      if (insent) {           /* if currently insent */
        nsents += 1;          /* increment no. of sentences */
      }
      break;                  /* break read loop */
    } /* if [a-zA-Z] */
    else if (isalpha (str[i])) {
      nchars += 1;            /* increment total no. of chars */
      inword = insent = 1;    /* set word and sentence flags 1 */
    }
  }

  /* compute l, s and index */
  l = (double) nchars / nwords * 100.;
  s = (double) nsents / nwords * 100.;
  index = 0.0588 * l - 0.296 * s - 15.8;

  if (index &gt; 0) {            /* round index value */
    index += 0.5;
  }
  else {
    index -= 0.5;
  }

#ifdef DEBUG
  printf (&quot;\nnchars : %d\nnwords : %d\nnsents : %d\n&quot;
          &quot;L      : %.2f\nS      : %.2f\nindex  : %d\n\n&quot;,
          nchars, nwords, nsents, l, s, (int)index);
#endif

  return index;       /* return index as int */
}

int main (void) {

  char *s = get_string (&quot;Text: &quot;);          /* get string */
  int cl_index = coleman_liau_index (s);    /* compute (int) index */

  if (cl_index &lt; 1) {                       /* classify result */
    puts (&quot;Below Grade 1&quot;);
  }
  else if (cl_index &gt;= 16) {
    puts (&quot;Grade 16+&quot;);
  }
  else {
    printf (&quot;Grade %d\n&quot;, cl_index);
  }
}

(the use of char *s instead of string s is intentional, see Is it a good idea to typedef pointers? (Answer: No except for function pointers which is fine for a wholly different set of reasons))

Note the #ifdef DEBUG that allows you to turn on/off the output of the char, word, sentence counts, the values of L and S and the index value simply by including the DEBUG define in your compiler string. For gcc/clang that is -DDEBUG, for the microsoft compiler, that's /DDEBUG. You can also just put #define DEBUG at the top of the code and do it that way.

Also note, you can write the DEBUG printf() as follows if it makes more sense to you:

  printf (&quot;\n&quot;
          &quot;nchars : %d\n&quot;
          &quot;nwords : %d\n&quot;
          &quot;nsents : %d\n&quot;
          &quot;L      : %.2f\n&quot;
          &quot;S      : %.2f\n&quot;
          &quot;index  : %d\n\n&quot;,
          nchars, nwords, nsents, l, s, (int)index);

(adjacent string literals are concatenated by the compiler during an early compilation phase before the code is generated. That allows you to make your outputs readable to ensure proper spacing, etc... and the compiler will join them together for you)

Example Use/Output

With DEBUG defined, the output for the given examples is:

$ ./bin/readability
text: Congratulations! Today is your day. You&#39;re off to Great Places! You&#39;re off and away!
nchars : 65
nwords : 14
nsents : 4
L      : 464.29
S      : 28.57
index  : 3
Grade 3

and

$ ./bin/readability
text: 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.
nchars : 214
nwords : 56
nsents : 4
L      : 382.14
S      : 7.14
index  : 5
Grade 5

and

$ ./bin/readability
text: As the average number of letters and words per sentence increases, the Coleman-Liau index gives the text a higher reading level. If you were to take this paragraph, for instance, which has longer words and sentences than either of the prior two examples, the formula would give the text an twelfth-grade reading level.
nchars : 258
nwords : 53
nsents : 2
L      : 486.79
S      : 3.77
index  : 12
Grade 12

All of which match the values provided on the CS50 Readability page. (as it does for all of the additional examples given at the end of the problem statement)

Without DEBUG defined, the code produces the exact output called for in the problem statement.

Whether you use a single loop, or just fix your three-loop as discussed in the start of the answer, you also need to round(0.0588 * L - 0.296 * S - 15.8) the entire calculation, not just the first part as you attempted. If you don't want to link with the math library, you can simply do it manually by adding or subtracting 0.5 depending whether the index result is positive or negative, respectively before taking the integer part of the double value as your index.

Look things over and let me know if you have questions.

huangapple
  • 本文由 发表于 2023年6月8日 08:23:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427874.html
匿名

发表评论

匿名网友

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

确定