我在UNIX上运行的C程序中编写了一个程序,它计算输入文本文件中每个字母的数量。对于这样的文件:
'猫坐在绿色的垫子上'
输出如下:
The letter ’a’ occurs 3 times.
The letter ’c’ occurs 1 times.
The letter ’e’ occurs 4 times.
The letter ’g’ occurs 1 times.
The letter ’h’ occurs 2 times.
The letter ’m’ occurs 1 times.
The letter ’n’ occurs 2 times.
The letter ’o’ occurs 1 times.
The letter ’r’ occurs 1 times.
The letter ’s’ occurs 1 times.
The letter ’t’ occurs 5 times.
5 *
4 * *
4 * *
3 * * *
3 * * *
2 * * * * *
2 * * * * *
1 * * * ** *** ***
1 * * * ** *** ***
0 **************************
0 **************************
... abcdefghijklmnopqrstuvwxyz
图表表示字母出现的次数。 (如果超过10,我只需在第10行后加上'+')。我目前编写的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void drawGraph(int letters[26], char alpha[26]);
void printLetters(int letters[26], char alpha[26]);
void getLetters(FILE *fp, int letters[26], char alpha[26]);
int main(int argc, char *argv[]) {
FILE *fp;
int letters[26] = { 0 };
char alpha[26] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };
int indexedAlpha[256] = { 0 };
int j = 1;
for (i = 97; i <= 127; i++)
{
indexedAlpha[i] = j;
j++;
}
//open file
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Cannot open file");
exit(EXIT_FAILURE);
}
getLetters(fp, letters, alpha);
printLetters(letters, alpha);
printf("\n");
drawGraph(letters, alpha);
printf("\n");
return EXIT_SUCCESS;
}
void getLetters(FILE *fp, int letters[26], char alpha[26]) {
int c;
for (int i = 0; (c = fgetc(fp)) != EOF; i++)
{
c = fgetc(fp);
if ( isalpha(c) )
{
for ( int j = 0; j < 26; j++ ) //find which letter it is
{
if( c == alpha[j] )
{
letters[j]++;
break;
}
}
}
}
}
void printLetters(int letters[26], char alpha[26]) {
for( int i = 0; i < 26; i++ )
{
if(letters[i] != 0){
printf("The letter '%c' occurs %d times.\n", alpha[i], letters[i]);
}
}
}
void drawGraph(int letters[26], char alpha[26]) {
int x = 11;
int y;
while(x >= 0)
{
y = 0;
while (y < 2)
{
if (x == 10)
{
printf(" %d ", x);
}
else if (x == 11)
{
printf(" ");
}
else
{
printf(" %d ", x);
}
for( int i = 0; i < 26; i++ )
{
if(letters[i] > 10)
{
printf("+");
letters[i] = 10;
y++; // Break out of while loop
}
else if(letters[i] == x)
{
printf("*");
}
else
{
printf(" ");
}
if (letters[i] == x && y == 1)
{
letters[i] = letters[i] - 1;
}
}
printf("\n");
y++;
}
x--;
}
printf("... ");
for( int i = 0; i < 26; i++ )
{
printf("%c", alpha[i]);
}
}
但是我目前的代码有两个问题。 1.我总是打印出10个Y轴点,我只想根据需要打印出多少个Y轴点,实现这个目标的最佳方法是什么? 2.目前只计算小写字符,我该如何处理?
任何符号或更好的方法都会非常感激,我还在努力学习!
谢谢!
答案 0 :(得分:2)
第二个问题对我来说似乎有点容易:
2. Currently only lower case characters are counted, how can i address this?
制作这样的结构:
typedef struct
{
char c;
int count;
}alpha;
alpha abc[26];
for(i=0 ; i<26 ; i++)
abc[i].count = 0; // Initialization of count for each alphabet
for(i=0;i<26; i++)
abc[i].c = 'a' + i;
通过这种方式,您可以跟踪每个字母的数量。
要打印文件中每个字母的“直方图”,您需要(11 + 1 + 1)
行
(表示至少13行,可以是用于分隔字符及其条形的额外行)
11
行11
次出现字母,1
为+
,1
为字母本身。{/ p>
但要打印这些线条,您需要在每个*
(您使用的直方图符号)之前处理有关空间的额外信息。
所以,循环遍历数组并打印出来,就像你的1st question
尝试这样:
int cnt;
for(cnt = 11 ; c >=0 ; c--)
{
for(i=0; i<26; i++)
{
if(abc[i].count >= cnt && cnt == 11)
{
space = abc[i].c - 'a';
printf("%*c",space,'+'); // setting indentation and printing
}
if(abc[i].count == cnt && cnt != 11)
{
space = abc[i].c - 'a';
printf("%*c",space,'*'); //// setting indentation and printing
}
printf("\n");
} //end of inner for loop
} // end of outer for loop
printf("abcdefghijklmnopqrstuvwxyz\n");
答案 1 :(得分:1)
不同的数据表示可以简化您的程序。
使用一个表来保存所有可能的一个字节字符; char的字节值作为键;出现次数是val。
注意使用while ((c = getchar()) != EOF)
;读取输入的习惯用法一次一个字节 - 你的getLetters()例程跳过其他所有字符。
下面的程序处理大写和小写字母;但仅限于一字节编码 - 它不能正确处理utf8,utf16等。有关文本编码的更多信息,请阅读此article。什么isalpha()视为一个字母取决于当前的语言环境,可以通过setlocale改变
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
enum { NROWS = 10 };
void draw_line(int count[], double scale, int level);
void draw(int count[]);
int main() {
int count[UCHAR_MAX+1] = {0};
int c;
while ((c = getchar()) != EOF)
count[c]++;
for (c = 0; c <= UCHAR_MAX; c++)
if (isalpha(c) && count[c] != 0)
printf("%c %d\n", c, count[c]);
draw(count);
return 0;
}
我的绘图版本,缩放y值而不是打印&#39; +&#39;对于大值。它只打印出多少&#34; y轴星形&#34;通过将计数与y轴的水平进行比较,可以得到它。
void draw(int count[]) {
int c, i;
int max = 0;
double scale;
for (c = 0; c <= UCHAR_MAX; c++)
if (isalpha(c) && count[c] > max)
max = count[c];
scale = (max == 0) : 1.0 : (double)max / NROWS;
for (i = NROWS; i > 0; i--)
draw_line(count, scale, i);
for (c = 0; c <= UCHAR_MAX; c++)
if (isalpha(c))
putchar(c);
putchar('\n');
}
void draw_line(int count[], double scale, int level) {
int c;
for (c = 0; c <= UCHAR_MAX; c++) {
if (isalpha(c) && count[c] / scale >= level)
putchar('*');
else if (isalpha(c))
putchar(' ');
}
putchar('\n');
}
图表的示例输出:
$ ./countchars < countchars.c
[..snip..]
*
* *
* *
* * * *
* * * * *
* * * * * * *
* * * * * ** * **
* *** ** * ** * **
* * **** ** * *** ****
* * * * * * * * **** ** ***** ******
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz