2013-08-07 40 views
11

Tôi là người mới bắt đầu trong lập trình C và hệ thống. Đối với bài tập về nhà, tôi cần viết chương trình đọc đầu vào từ các dòng phân tích cú pháp stdin thành các từ và gửi các từ tới các tiến trình sắp xếp bằng cách sử dụng hàng đợi thông báo System V (ví dụ: đếm từ). Tôi bị kẹt ở phần đầu vào. Tôi đang cố gắng xử lý dữ liệu nhập, xóa các ký tự không phải alpha, đặt tất cả các từ alpha trong chữ thường và cuối cùng, chia một dòng từ thành nhiều từ. Cho đến nay tôi có thể in tất cả các từ alpha trong trường hợp thấp hơn, nhưng có những dòng giữa các từ, mà tôi tin là không chính xác. Ai đó có thể xem và đưa cho tôi một số gợi ý?Đọc từ một tệp văn bản và phân tích các dòng thành các từ trong C

Ví dụ từ một tập tin văn bản: Dự án Gutenberg EBook của The Iliad của Homer, bởi Homer

Tôi nghĩ rằng kết quả chính xác nên được:

the 
project 
gutenberg 
ebook 
of 
the 
iliad 
of 
homer 
by 
homer 

Nhưng đầu ra của tôi là như sau:

project 
gutenberg 
ebook 
of 
the 
iliad 
of 
homer 
         <------There is a line there 
by 
homer 

Tôi nghĩ dòng trống là do khoảng cách giữa "," và "theo". Tôi đã thử những thứ như "nếu isspace (c) sau đó không làm gì", nhưng nó không hoạt động. Mã của tôi là dưới đây. Bất kỳ trợ giúp hoặc đề xuất nào được đánh giá cao.

#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; 
} 

EDIT **

tôi sửa mã của tôi và cuối cùng đã đầu ra chính xác:

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; 
} 
+4

+1 để đăng mã hợp lý. Một gợi ý: 'perror (input)'. Có vài điều tồi tệ hơn thông báo lỗi mà không có tên tệp. –

+0

chức năng strtok có thể hữu ích. – keety

Trả lời

6

Tôi nghĩ rằng bạn chỉ cần bỏ qua bất kỳ ký tự không phải alpha nào! isalpha (c) nếu không chuyển đổi thành chữ thường. Bạn sẽ cần phải theo dõi khi bạn tìm thấy một từ trong trường hợp này.

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); 
    } 
} 

Nếu bạn cần xử lý dấu nháy trong các từ như "không" thì điều này nên thực hiện.

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); 
    } 
} 
+0

Điều đó hoạt động! Cảm ơn bạn! =) – user2203774

0

Dường như bạn đang tách từ bằng dấu cách, vì vậy tôi nghĩ chỉ

while ((c =fgetc(input_file)) != EOF) 
{ 
    if (isalpha(c)) 
    { 
     c = tolower(c); 
     putchar(c); 
    } 
    else if (isspace(c)) 
    { 
     putchar('\n'); 
    } 
} 

cũng sẽ hoạt động. Miễn là văn bản nhập của bạn sẽ không có nhiều khoảng trống giữa các từ.

+0

Có một dấu phẩy trong đầu vào không được sao chép vào đầu ra. Bản tóm tắt cũng mô tả "từ". Tuy nhiên, ngắn gọn và đơn giản; dễ điều chỉnh. – usr2564301

1

Tôi nghi ngờ bạn thực sự muốn xử lý tất cả ký tự không theo thứ tự chữ cái làm dấu tách, không chỉ xử lý dấu cách làm dấu tách và bỏ qua ký tự không phải chữ cái. Nếu không, foo--bar sẽ hiển thị dưới dạng một từ foobar, phải không? Tin tốt là, điều đó làm mọi thứ dễ dàng hơn. Bạn có thể xóa mệnh đề isspace và chỉ sử dụng mệnh đề else.

Trong khi đó, cho dù bạn xử lý các dấu chấm câu đặc biệt hay không, bạn vẫn gặp vấn đề: Bạn in một dòng mới cho bất kỳ không gian nào cả. Vì vậy, một dòng kết thúc bằng \r\n hoặc \n hoặc thậm chí một câu kết thúc bằng ., sẽ in một dòng trống. Cách rõ ràng xung quanh đó là để theo dõi các ký tự cuối cùng, hoặc một lá cờ, vì vậy bạn chỉ in một dòng mới nếu bạn đã in một lá thư trước đó.

Ví dụ:

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; 
} 

Nhưng bạn có thực sự muốn đối xử với tất cả các dấu chấm câu giống nhau không? Tuyên bố vấn đề ngụ ý rằng bạn làm, nhưng trong cuộc sống thực, đó là một chút kỳ lạ. Ví dụ: foo--bar có thể hiển thị dưới dạng các từ riêng biệt foobar, nhưng phải it's thực sự hiển thị dưới dạng các từ riêng biệt its?Đối với vấn đề đó, sử dụng isalpha làm quy tắc của bạn cho "ký tự từ" cũng có nghĩa là, 2nd sẽ hiển thị là nd. Vì vậy, nếu isascii không phải là quy tắc thích hợp cho trường hợp sử dụng của bạn để phân biệt các ký tự từ các ký tự phân cách, bạn sẽ phải viết hàm của riêng bạn để tạo nên sự phân biệt đúng. Bạn có thể dễ dàng thể hiện một quy tắc như vậy trong logic (ví dụ: isalnum(c) || c == '\'') hoặc với một bảng (chỉ là một mảng 128 ints, vì vậy hàm này là c >= 0 && c < 128 && word_char_table[c]). Làm theo cách đó có thêm lợi ích mà sau này bạn có thể mở rộng mã của mình để xử lý bằng Latin-1 hoặc Unicode hoặc để xử lý văn bản chương trình (có các ký tự từ khác với văn bản tiếng Anh) hoặc…

+0

Lưu ý rằng điều này sẽ dừng một số dấu chấm câu có thể cần thiết để giữ lại, bao gồm dấu gạch nối và dấu nháy đơn. bạn có thể cần phải đặc biệt trong trường hợp đó, và trong một số trường hợp (ví dụ: dấu gạch ngang theo sau là dòng mới) sẽ loại bỏ chúng. Nếu không, các từ như "không" sẽ không giữ lại các biểu diễn gốc của chúng. – WhozCraig

+0

@WhozCraig: Có; kể từ khi OP rõ ràng bỏ qua tất cả dấu chấm câu, tôi đã chọn làm như vậy. Nhưng nếu đó không phải là những gì anh ta muốn, anh ta cần thêm mã cho điều đó. Tôi sẽ thêm một lưu ý về điều đó vào câu trả lời. – abarnert

+0

Vấn đề với việc cho phép 'không' là nó cũng nên cho phép' các lớp'' là "một từ duy nhất". Nó phụ thuộc vào đầu vào cho dù các cụm từ trích dẫn đơn lẻ sẽ là vấn đề * tiếp theo *, sau đó. – usr2564301

Các vấn đề liên quan