英文:
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("Text: ");
{
printf("%s\n", text);
}
int count_letters(string letters);
// count letters
int letters = 0;
int n = 0;
while (text[n])
{
if (isalpha(text[n]) != '\0')
{
letters++;
}
n++;
} //print number of letters
printf("%i letters\n", letters);
//count words
int count_words(string words);
int words = 0;
int x = 0;
while (text[x])
{
if ((text[x]) == ' ')
{
words++;
}
x++;
} //print number of words
printf("%i words\n", 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("%i sentences\n", 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 < 1)
{
printf("Before Grade 1\n");
}
else if (grade > 16)
{
printf("Grade 16+\n");
}
else
{
printf("Grade %i\n", 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 ' '
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 '
or ';'
or '"'
, 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 "Today is your day. You"
, "re off to Great Places"
"You"
and "re off and away"
to all be separate sentences.
Instead, as the instructions state, you should only consider '.'
, '?'
and '!'
to mark end-of-sentence. A simple if
checking all three conditions is all you need, e.g.
if (text展开收缩 == '.' || text展开收缩 == '?' || text展开收缩 == '!') {
...
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 ' '
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 '
or ';'
or '"'
, 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 "Today is your day. You"
, "re off to Great Places"
"You"
and "re off and away"
to all be separate sentences.
Instead, as the instructions state, you should only consider '.'
, '?'
and '!'
to mark end-of-sentence. A simple if
checking all three conditions is all you need, e.g.
if (text展开收缩 == '.' || text展开收缩 == '?' || text展开收缩 == '!') {
...
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.
if (isspace (str[i])) {
to check if you need to increment your word count. Within this condition, you simply checkif (inword) {
to know if you should increment your word count;else if (str[i] == '.' || str[i] == '?' || str[i] == '!') {
to check for an end-of-sentence condition, and then you checkif (insent) {
to know if you should increment your sentence count;else if (!str[i]) {
to check your end-of-string andbreak
the loop (equivalent toif (str[i] == '\0')
and plain oldif (str[i] == 0)
- lastly,
else if (isalpha (str[i])) {
to know if you should increment your character count and set your state variablesinword = 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 <cs50.h>
#include <stdio.h>
#include <ctype.h>
/* 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] == '.' || str[i] == '?' || str[i] == '!') {
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 > 0) { /* round index value */
index += 0.5;
}
else {
index -= 0.5;
}
#ifdef DEBUG
printf ("\nnchars : %d\nnwords : %d\nnsents : %d\n"
"L : %.2f\nS : %.2f\nindex : %d\n\n",
nchars, nwords, nsents, l, s, (int)index);
#endif
return index; /* return index as int */
}
int main (void) {
char *s = get_string ("Text: "); /* get string */
int cl_index = coleman_liau_index (s); /* compute (int) index */
if (cl_index < 1) { /* classify result */
puts ("Below Grade 1");
}
else if (cl_index >= 16) {
puts ("Grade 16+");
}
else {
printf ("Grade %d\n", 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 ("\n"
"nchars : %d\n"
"nwords : %d\n"
"nsents : %d\n"
"L : %.2f\n"
"S : %.2f\n"
"index : %d\n\n",
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're off to Great Places! You'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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论