2012-04-03 41 views
9

Vì UNIX có tất cả các chương trình giống như bộ lọc tuyệt vời (chẳng hạn như grep, sed, tr và vv), cách dễ nhất để viết một trong những chương trình nào trong tiêu chuẩn C?Làm cách nào để viết chương trình lọc trong C?

Bằng bộ lọc, ý tôi là một chương trình đọc đầu vào tiêu chuẩn, thực hiện một số thao tác của dữ liệu và sau đó ghi nó vào đầu ra tiêu chuẩn. Đây là hữu ích trong việc xây dựng đường ống dẫn các lệnh, mỗi thực hiện một số thao tác bổ sung của dữ liệu, chẳng hạn như:

grep xyzzy input.file | tr '[A-Z]' '[a-z]' | sed 's/plugh/PLUGH/g' 

(mỗi trong những biểu tượng ống | kết nối đầu ra tiêu chuẩn của lệnh trước đó để đầu vào tiêu chuẩn của tiếp theo, do đó ẩn dụ đường ống dẫn).

Giả sử tôi cần một người đã chuyển đổi tất cả các ký tự viết hoa thành chữ thường. Và, vâng, tôi nhận ra đặc biệt vấn đề này có thể được giải quyết với các UNIX:

tr '[A-Z]' '[a-z]' 

nhưng đó chỉ là một ví dụ .

Điều tôi thực sự sau là mã nguồn C chuẩn đơn giản nhất để thực hiện một bộ lọc như vậy.

+2

Tôi có thiếu cái gì? Ngày 1 tháng 4 là một vài ngày trước ... –

+1

Đối với tất cả các công cụ bạn đã đề cập, bạn có thể dễ dàng tìm thấy mã nguồn. Tại sao không có một cái nhìn tại đó để tìm hiểu cách chúng được triển khai? –

+2

@Michael, không, nó xuất hiện khi tôi trả lời một câu hỏi khác, và tôi nhận ra không có câu hỏi nào về việc này. Theo hướng dẫn (SO có nghĩa là cho tất cả các cấp của người dùng và trả lời các câu hỏi của riêng bạn), tôi nghĩ rằng tôi muốn đưa nó lên. Rõ ràng, _I_ biết làm thế nào để làm điều đó, nhưng tôi sẽ không rep-con điếm, thay vào đó cho phép người khác trả lời (trừ khi họ không trong một người đi cùng của ngày trong trường hợp đó, tôi sẽ rep-whore đến tối đa :-) – paxdiablo

Trả lời

6

Bạn có thể sử dụng getline như mô tả của @hroptatyr, nhưng bạn có thể làm điều gì đó đơn giản hơn rất nhiều:

#include <stdio.h> 
#include <ctype.h> 
int main(void) { 
    int c; 
    while ((c = getchar()) != EOF) 
     putchar(tolower(c)); 
    return 0; 
} 
+3

Tôi nghĩ rằng ai đó thực sự nên giải thích điểm chính: bộ lọc là chương trình đọc 'stdin' làm điều gì đó (có thể bao gồm không làm gì cả, chẳng hạn như 'cat') vào dữ liệu và ghi dữ liệu đã chuyển đổi thành' stdout'. Tất nhiên, nhiều bộ lọc làm nhiều hơn thế, chẳng hạn như đọc/ghi vào các tệp khác với 'stdin' /' stdout' nếu được chỉ dẫn bởi các tùy chọn. Nhưng tôi nghĩ đó là khái niệm cốt lõi của một bộ lọc. –

3

Trong pseudo-code:

do 
    line = read(stdin); 
    filter(line); 
    print(line); 
until no_more_lines 

Trong mã thực:

char *line = NULL; 
size_t len = 0U; 
ssize_t n; 

while ((n = getline(&line, &len, stdin)) >= 0) { 
     /* LINE is of length N, filter it */ 
     filter(line, n); 
     /* print it */ 
     fputs(line, stdout); 
} 
free(line); 

filter() trông giống như:

static void filter(char *line, size_t length) 
{ 
     while ((*line++ = tolower(*line))); 
} 

Chỉnh sửa: Đừng quên để xác định _POSIX_C_SOURCE >= 200809L hoặc _XOPEN_SOURCE >= 700 . Và đừng quên bao gồm stdio.h cho getline()ctype.h cho tolower().

+0

'getline'? Whassat? :-) – paxdiablo

+0

@paxdiablo Một hàm có thể được xác định ở nơi khác. – glglgl

+0

@paxdiablo làm 'man 3 getline' và được khai sáng. –

3

Một chương trình "lọc" chỉ đơn giản là một chương trình mà đọc từ dòng đầu vào tiêu chuẩn (stdin) và ghi vào luồng đầu ra tiêu chuẩn (stdout). Trước khi viết dữ liệu đã đọc, dữ liệu thường được chuyển đổi theo một cách nào đó (nếu bạn không tạo ra bất kỳ phép chuyển đổi hoặc lọc nào, về cơ bản bạn đã viết một chương trình cat chỉ in ra bất kỳ thứ gì được trao cho nó). Sức mạnh của chương trình lọc xuất phát từ thực tế là họ không ra lệnh nơi đầu vào của họ đến từ đâu hoặc nơi đầu ra sẽ đến. Thay vào đó, nó tùy thuộc vào người gọi của chương trình để cung cấp các kênh đầu vào/đầu ra.

Cốt lõi của một chương trình lọc có thể giống như thế này (bạn có thể sử dụng như là một khuôn mẫu cho các chương trình lọc của riêng bạn):

#include <stdio.h> 

int filter(FILE *input, FILE *output); 

int main(void) 
{ 
    const int retval = filter(stdin, stdout); 
    fflush(stdout); 
    return retval; 
} 

Vậy là xong. Công việc thực tế được thực hiện bởi một hàm filter thực hiện phép biến đổi mà bạn mong muốn.Ví dụ, đây là một chương trình đơn giản mà đọc ký tự từ tập tin đầu vào, biến chúng thành chữ thường, và sau đó in chúng lại thành file đầu ra:

#include <stdio.h> 
#include <ctype.h> /* for tolower */ 

int filter(FILE *input, FILE *output) 
{ 
    while (!feof(input)) { 
     if (ferror(input)) { 
      return 1; 
     } 
     fputc(tolower(fgetc(input)), output); 
    } 
    return 0; 
} 

int main(void) 
{ 
    const int retval = filter(stdin, stdout); 
    fflush(stdout); 
    return retval; 
} 

Nếu bạn biên dịch và chạy chương trình này, nó sẽ chỉ đơn giản là ngồi ở đó và kiên nhẫn chờ dữ liệu đọc từ tập tin đầu vào tiêu chuẩn stdin. Tệp này thường được liên kết với bảng điều khiển, có nghĩa là bạn phải nhập một số dữ liệu bằng tay. Tuy nhiên, các lệnh shell thực hiện một tính năng gọi là các đường ống cho phép bạn kết nối đầu ra của một lệnh với đầu vào của một lệnh khác. Điều này cho phép soạn nhiều chương trình thành pipeline để tạo các lệnh mạnh mẽ.

Đây là cách chúng ta có thể sử dụng chương trình lọc của chúng tôi (giả sử bạn được gọi là kết quả nhị phân lower):

$ echo Hello | lower 
hello 
$ 

Kể từ khi chương trình lọc của chúng tôi không xác định nơi dữ liệu được đọc đến từ, chúng ta có thể kết hợp nó với tất cả các loại chương trình sản xuất đầu ra trên stdout. Ví dụ, dưới đây là cách bạn có thể nhận được một tập tin toàn bộ như chữ thường (bạn có thể sử dụng trên các máy Windows type thay):

$ cat myfile.txt 
Hello, World! 
This is a simple test. 

$ cat myfile.txt | lower 
hello, world! 
this is a simple test. 

$ 
+0

'fflush (stdout);' dường như vô ích: "Nếu hàm' main' trả về người gọi ban đầu, [...] tất cả các tệp đang mở là đóng (vì thế tất cả các luồng đầu ra đều được xóa) trước khi chấm dứt chương trình . " (ISO/IEC 9899: 1999, 7.9.13, §5). –

+0

@undur_gongor: Để được hoenst, tôi đồng ý; Tôi không có cuộc gọi 'fflush' trong phiên bản đầu tiên của mình.Tuy nhiên, khi thử chương trình trên một hộp Windows XP, tôi nhận thấy rằng tôi không thấy bất kỳ đầu ra nào. Rõ ràng đỏ bừng 'stdout' đã giúp - tôi không bận tâm kiểm tra thêm nữa (tôi có ít kinh nghiệm với các C API trên Windows). –

-4
L1: 
mov dx,081 
mov cx,1 
mov bx,0 
mov ax,03f00 
int 021 
cmp ax,0 
je L2 
cmp b[081],'a' 
jb L3 
cmp b[081],'z' 
ja L3 
sub b[081],020 
L3: 
mov dx,081 
mov cx,1 
mov bx,1 
mov ax,04000 
int 021 
jmp L1 
L2: 
mov ax,04c00 
int 021 

; Example in A86 Assembler see eji.com for A86/D86 
+1

Bạn có thể giải thích thêm về điều này không? –

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