我是C和系统编程的初学者。对于家庭作业,我需要编写一个程序,该程序将stdin解析行的输入读入单词,并使用System V消息队列(例如,计数单词)将单词发送到排序子进程。我被困在输入部分。我正在尝试处理输入,删除非字母字符,将所有字母单词放在小写字母中,最后将一行单词分成多个单词。到目前为止,我可以用小写字母打印所有字母单词,但字母之间有一些线,我认为这是不正确的。有人可以看看并给我一些建议吗?
来自文本文件的示例:Homer的荷马伊利亚特的古腾堡项目电子书
我认为正确的输出应该是:
the
project
gutenberg
ebook
of
the
iliad
of
homer
by
homer
但我的输出如下:
project
gutenberg
ebook
of
the
iliad
of
homer
<------There is a line there
by
homer
我认为空行是由“,”和“by”之间的空格引起的。我尝试了“if isspace(c)然后什么都不做”之类的事情,但它不起作用。我的代码如下。任何帮助或建议表示赞赏。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
//Main Function
int main (int argc, char **argv)
{
int c;
char *input = argv[1];
FILE *input_file;
input_file = fopen(input, "r");
if (input_file == 0)
{
//fopen returns 0, the NULL pointer, on failure
perror("Canot open input file\n");
exit(-1);
}
else
{
while ((c =fgetc(input_file)) != EOF )
{
//if it's an alpha, convert it to lower case
if (isalpha(c))
{
c = tolower(c);
putchar(c);
}
else if (isspace(c))
{
; //do nothing
}
else
{
c = '\n';
putchar(c);
}
}
}
fclose(input_file);
printf("\n");
return 0;
}
编辑 **
我编辑了我的代码并最终获得了正确的输出:
int main (int argc, char **argv)
{
int c;
char *input = argv[1];
FILE *input_file;
input_file = fopen(input, "r");
if (input_file == 0)
{
//fopen returns 0, the NULL pointer, on failure
perror("Canot open input file\n");
exit(-1);
}
else
{
int found_word = 0;
while ((c =fgetc(input_file)) != EOF )
{
//if it's an alpha, convert it to lower case
if (isalpha(c))
{
found_word = 1;
c = tolower(c);
putchar(c);
}
else {
if (found_word) {
putchar('\n');
found_word=0;
}
}
}
}
fclose(input_file);
printf("\n");
return 0;
}
答案 0 :(得分:6)
我认为你只需要忽略任何非alpha字符!isalpha(c)否则转换为小写。在这种情况下,当你找到一个单词时,你需要跟踪。
int found_word = 0;
while ((c =fgetc(input_file)) != EOF )
{
if (!isalpha(c))
{
if (found_word) {
putchar('\n');
found_word = 0;
}
}
else {
found_word = 1;
c = tolower(c);
putchar(c);
}
}
如果你需要在诸如“不是”这样的词中处理撇号,那么这应该这样做。
int found_word = 0;
int found_apostrophe = 0;
while ((c =fgetc(input_file)) != EOF )
{
if (!isalpha(c))
{
if (found_word) {
if (!found_apostrophe && c=='\'') {
found_apostrophe = 1;
}
else {
found_apostrophe = 0;
putchar('\n');
found_word = 0;
}
}
}
else {
if (found_apostrophe) {
putchar('\'');
found_apostrophe == 0;
}
found_word = 1;
c = tolower(c);
putchar(c);
}
}
答案 1 :(得分:1)
我怀疑你真的想要将所有非字母字符作为分隔符处理,而不仅仅将空格处理为分隔符并忽略非字母字符。否则,foo--bar
将显示为单个字foobar
,对吧?好消息是,这会让事情变得更容易。您可以删除isspace
子句,只使用else
子句。
与此同时,无论你是否特别处理标点符号,你都会遇到问题:你可以为任何空间打印换行符。因此,以\r\n
或\n
结尾的行,或者以.
结尾的句子,将打印一个空行。显而易见的方法是跟踪最后一个字符或标记,这样如果您之前打印过一个字母,则只打印换行符。
例如:
int last_c = 0
while ((c = fgetc(input_file)) != EOF )
{
//if it's an alpha, convert it to lower case
if (isalpha(c))
{
c = tolower(c);
putchar(c);
}
else if (isalpha(last_c))
{
putchar(c);
}
last_c = c;
}
但你真的想把所有的标点符号都对待吗?问题陈述意味着你这样做,但在现实生活中,这有点奇怪。例如,foo--bar
可能应该显示为单独的单词foo
和bar
,但it's
应该显示为单独的单词it
和s
}?就此而言,使用isalpha
作为“单词字符”的规则也意味着,2nd
将显示为nd
。
因此,如果isascii
不适合您的用例区分单词字符和分隔符,则必须编写自己的函数来进行正确的区分。您可以在逻辑(例如isalnum(c) || c == '\''
)或表(仅128个整数的数组,因此函数为c >= 0 && c < 128 && word_char_table[c]
)中轻松表达此类规则。这样做有一个额外的好处,你可以稍后扩展你的代码来处理Latin-1或Unicode,或处理程序文本(其中包含不同于英文文本的单词字符),或...
答案 2 :(得分:0)
看来你是用空格分隔单词,所以我想只是
while ((c =fgetc(input_file)) != EOF )
{
if (isalpha(c))
{
c = tolower(c);
putchar(c);
}
else if (isspace(c))
{
putchar('\n');
}
}
也会奏效。如果您的输入文本在单词之间不会有多个空格。